前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Elasticsearch学习(五)Elasticsearch中的mapping问题,Search 搜索详解

Elasticsearch学习(五)Elasticsearch中的mapping问题,Search 搜索详解

作者头像
一写代码就开心
发布2021-03-02 14:46:25
1.7K0
发布2021-03-02 14:46:25
举报
文章被收录于专栏:java和python

Elasticsearch中的mapping问题

Mapping在Elasticsearch中是非常重要的一个概念。决定了一个index中的field使用什么数据格式存储,使用什么分词器解析,是否有子字段等。

为什么要学习Mapping?

如果没有mapping所有text类型属性默认都使用standard分词器。所以如果希望使用IK分词就必须配置自定义mapping。

1 mapping核心数据类型

Elasticsearch中的数据类型有很多,在这里只介绍常用的数据类型。 只有text类型才能被分词。其他类型不允许。 文本(字符串):text 整数:byte、short、integer、long 浮点型:float、double 布尔类型:boolean 日期类型:date 数组类型:array {a:[]} 对象类型:object {a:{}} 不分词的字符串(关键字): keyword

2 dynamic mapping对字段的类型分配

true or false -> boolean 123 -> long 123.123 -> double 2018-01-01 -> date hello world -> text [] -> array {} -> object 在上述的自动mapping字段类型分配的时候,只有text类型的字段需要分词器。默认分词器是standard分词器。

3 查看索引mapping

可以通过命令查看已有index的mapping具体信息,语法如下: GET 索引名/_mapping

如:

GET test_index/_mapping

结果:

代码语言:javascript
复制
{
  "test_index": { # 索引名
    "mappings": { # 映射列表
      "test_type": { # 类型名
        "properties": { # 字段列表
          "age": { # 字段名
            "type": "long" # 字段类型
          },
          "gender": {
            "type": "text",
            "fields": { # 子字段列表
              "keyword": { # 子字段名
                "type": "keyword", # 子字段类型,keyword不进行分词处理的文本类型
                "ignore_above": 256 # 子字段存储数据长度
              }
            }
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

4 custom mapping

可以通过命令,在创建index和type的时候来定制mapping映射,也就是指定字段的类型和字段数据使用的分词器。 手工定制mapping时,只能新增mapping设置,不能对已有的mapping进行修改。 如:有索引a,其中有类型b,增加字段f1的mapping定义。后续可以增加字段f2的mapping定义,但是不能修改f1字段的mapping定义。 通常都是手工创建index,并进行各种定义。如:settings,mapping等。

4.1创建索引时指定mapping

代码语言:javascript
复制
语法:
PUT 索引名称
{
  "mappings":{
    "类型名称":{
      "properties":{
        "字段名":{
          "type":类型,
          ["analyzer":字段的分词器,]
          ["fields":{
            "子字段名称":{
              "type":类型,
              "ignore_above":长度限制
}
}]
}
}
}
}
}

举一个例子:

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
PUT /test_index
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1
  },
  "mappings": {
    "test_type":{
      "properties": {
        "author_id" : {
          "type": "byte",
          "index": false
        },
        "title" : {
          "type": "text",
          "analyzer": "ik_max_word",
          "fields": {
            "keyword" : {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "content" : {
          "type": "text",
          "analyzer": "ik_max_word"
        },
        "post_date" : {
          "type": "date"
        }
      }
    }
  }
}
代码语言:javascript
复制
"index" - 是否可以作为搜索索引。可选值:true | false
"analyzer" - 指定分词器。
"type" - 指定字段类型

Search 搜索详解

代码语言:javascript
复制
PUT test_search
{
  "mappings": {
    "test_type" : {
      "properties": {
        "dname" : { 
          "type" : "text",
          "analyzer": "standard"
        },
        "ename" : {
          "type" : "text",
          "analyzer": "standard"
        },
        "eage" : {
          "type": "long"
        },
        "hiredate" : {
          "type": "date"
        },
        "gender" : {
          "type" : "keyword"
        }
      }
    }
  }
}
代码语言:javascript
复制
POST test_search/test_type/_bulk
{ "index": {}}
{ "dname" : "Sales Department", "ename" : "张三", "eage":20, "hiredate" : "2019-01-01", "gender" : "男性" }
{ "index": {}}
{ "dname" : "Sales Department", "ename" : "李四", "eage":21, "hiredate" : "2019-02-01", "gender" : "男性" }
{ "index": {}}
{ "dname" : "Development Department", "ename" : "王五", "eage":23, "hiredate" : "2019-01-03", "gender" : "男性" }
{ "index": {}}
{ "dname" : "Development Department", "ename" : "赵六", "eage":26, "hiredate" : "2018-01-01", "gender" : "男性" }
{ "index": {}}
{ "dname" : "Development Department", "ename" : "韩梅梅", "eage":24, "hiredate" : "2019-03-01", "gender" : "女性" }
{ "index": {}}
{ "dname" : "Development Department", "ename" : "钱虹", "eage":29, "hiredate" : "2018-03-01", "gender" : "女性" }

2query string search

search的参数都是类似http请求头中的字符串参数提供搜索条件的。 GET [/index_name/type_name/]_search[?parameter_name=parameter_value&…]

2.1全搜索

timeout参数:是超时时长定义。代表每个节点上的每个shard执行搜索时最多耗时多久。不会影响响应的正常返回。只会影响返回响应中的数据数量。 如:索引a中,有10亿数据。存储在5个shard中,假设每个shard中2亿数据,执行全数据搜索的时候,需要耗时1000毫秒。定义timeout为10毫秒,代表的是shard执行10毫秒,搜索出多少数据,直接返回。 在商业项目中,是禁止全数据搜索的。必须指定搜索的索引,类型和关键字。如果没有指定索引或类型,则代表开发目的不明确,需要重新做用例分析。如果没有关键字,称为索引内全搜索,也叫魔鬼搜索。

代码语言:javascript
复制
语法:
GET [索引名/类型名/]_search?timeout=10ms
代码语言:javascript
复制
get test_search/_search
代码语言:javascript
复制
{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 6,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test_search",
        "_type" : "test_type",
        "_id" : "tke_pXcBCmx352yzWc4R",
        "_score" : 1.0,
        "_source" : {
          "dname" : "Sales Department",
          "ename" : "张三",
          "eage" : 20,
          "hiredate" : "2019-01-01",
          "gender" : "男性"
        }
      },
      {
        "_index" : "test_search",
        "_type" : "test_type",
        "_id" : "uke_pXcBCmx352yzWc4R",
        "_score" : 1.0,
        "_source" : {
          "dname" : "Development Department",
          "ename" : "韩梅梅",
          "eage" : 24,
          "hiredate" : "2019-03-01",
          "gender" : "女性"
        }
      },
      {
        "_index" : "test_search",
        "_type" : "test_type",
        "_id" : "t0e_pXcBCmx352yzWc4R",
        "_score" : 1.0,
        "_source" : {
          "dname" : "Sales Department",
          "ename" : "李四",
          "eage" : 21,
          "hiredate" : "2019-02-01",
          "gender" : "男性"
        }
      },
      {
        "_index" : "test_search",
        "_type" : "test_type",
        "_id" : "uEe_pXcBCmx352yzWc4R",
        "_score" : 1.0,
        "_source" : {
          "dname" : "Development Department",
          "ename" : "王五",
          "eage" : 23,
          "hiredate" : "2019-01-03",
          "gender" : "男性"
        }
      },
      {
        "_index" : "test_search",
        "_type" : "test_type",
        "_id" : "uUe_pXcBCmx352yzWc4R",
        "_score" : 1.0,
        "_source" : {
          "dname" : "Development Department",
          "ename" : "赵六",
          "eage" : 26,
          "hiredate" : "2018-01-01",
          "gender" : "男性"
        }
      },
      {
        "_index" : "test_search",
        "_type" : "test_type",
        "_id" : "u0e_pXcBCmx352yzWc4R",
        "_score" : 1.0,
        "_source" : {
          "dname" : "Development Department",
          "ename" : "钱虹",
          "eage" : 29,
          "hiredate" : "2018-03-01",
          "gender" : "女性"
        }
      }
    ]
  }
}
代码语言:javascript
复制
结果:
{
  "took": 144, #请求耗时多少毫秒
  "timed_out": false, #是否超时。默认情况下没有超时机制,也就是客户端等待Elasticsearch搜索结束(无论执行多久),提供超时机制的话,Elasticsearch则在指定时长内处理搜索,在指定时长结束的时候,将搜索的结果直接返回(无论是否搜索结束)。指定超时的方式是传递参数,参数单位是:毫秒-ms。秒-s。分钟-m。
  "_shards": {
    "total": 1, #请求发送到多少个shard上
    "successful": 1,#成功返回搜索结果的shard
    "skipped": 0, #停止服务的shard
    "failed": 0 #失败的shard
  },
  "hits": {
    "total": 1, #返回了多少结果
    "max_score": 1, #搜索结果中,最大的相关度分数,相关度越大分数越高,_score越大,排位越靠前。
    "hits": [ #搜索到的结果集合,默认查询前10条数据。
      {
        "_index": "test_index", #数据所在索引
        "_type": "test_type", #数据所在类型
        "_id": "1", #数据的id
        "_score": 1, #数据的搜索相关度分数
        "_source": { # 数据的具体内容。
          "field": "value"
        }
      }
    ]
  }
}

2.2multi index搜索

**所谓的multi-index就是从多个index中搜索数据。**相对使用较少,只有在复合数据搜索的时候,可能出现。一般来说,如果真使用复合数据搜索,都会使用_all。

如:搜索引擎中的无条件搜索。(现在的应用中都被屏蔽了。使用的是默认搜索条件,执行数据搜索。 如: 电商中的搜索框默认值, 搜索引擎中的类别)

无条件搜索,在搜索应用中称为“魔鬼搜索”,代表的是,搜索引擎会执行全数据检索,效率极低,且对资源有非常高的压力。

代码语言:javascript
复制
语法:
GET _search

GET 索引名1,索引名2/_search # 搜索多个index中的数据

GET 索引名/类型名/_search # 所属一个index中type的数据

GET prefix_*/_search # 通配符搜索
GET *_suffix/_search

GET 索引名1,索引名2/类型名/_search # 搜索多个index中type的数据

GET _all/_search # _all代表所有的索引
 GET 索引名/_search?q=字段名:搜索条件

示例:get test_search/test_type/_search?q=eage:26 对搜索条件为中文支持不友好。

2.3分页搜索

默认情况下,Elasticsearch搜索返回结果是10条数据。从第0条开始查询。 size和from是es中具有特定含义的属性名。 语法:

代码语言:javascript
复制
GET 索引名/_search?size=10 # size查询数据的行数

GET 索引名/_search?from=0&size=10 # from 从第几行开始查询,行号从0开始。

2.4+/-搜索

代码语言:javascript
复制
语法:
GET 索引名/_search?q=字段名:条件

GET 索引名/_search?q=+字段名:条件

GET 索引名/_search?q=-字段名:条件
  • :和不定义符号含义一样,就是搜索指定的字段中包含key words的数据
  • : 与+符号含义相反,就是搜索指定的字段中不包含key words的数据 示例: 搜索dname中包含Sales单词的内容。dname使用standard分词器,会把内容进行拆分为单词。搜索Sales可以匹配到单词,但是搜索Sal是无法匹配到单词。 get test_search/test_type/_search?q=+dname:Sales

2.5排序

代码语言:javascript
复制
语法:GET 索引名/_search?sort=字段名:排序规则
排序规则: asc(升序) | desc(降序)
GET test_search/_search?sort=eage:asc

GET test_search/_search?sort=eage:desc

3 query DSL

DSL - Domain Specified Language , 特殊领域的语言。 请求参数是请求体传递的。在Elasticsearch中,请求体的字符集默认为UTF-8。

代码语言:javascript
复制
语法格式:
GET 索引名/_search
{
   "command":{ "parameter_name" : "parameter_value"}
}

3.1查询所有数据

代码语言:javascript
复制
GET 索引名/_search
{
   "query" : { "match_all" : {} }
}

3.2match search(项目搜索功能使用此命令)

全文检索。要求查询条件拆分后的任意词条与具体数据匹配就算搜索结果。

代码语言:javascript
复制
GET 索引名/_search
{
  "query": {
    "match": {
      "字段名": "搜索条件"
    }
  }
}

3.3phrase search

短语检索。要求查询条件必须和具体数据完全匹配才算搜索结果。其特征是: 1.对搜索条件进行拆词 2.把拆词当作一个整体,整体去索引(索引是存储内容被拆词后的结果)中匹配,必须严格匹配(存储内容拆词后是:北京,大兴,朝阳,条件拆词是:北京,朝阳。这种情况是不能被查询的,因为北京和朝阳之前还有大兴。)才能查询到

代码语言:javascript
复制
GET 索引名/_search
{
  "query": {
    "match_phrase": {
      "字段名": "搜索条件"
    }
  }
}

3.4range

代码语言:javascript
复制
范围比较搜索
GET 索引名/类型名/_search
{
  "query" : {
    "range" : {
      "字段名" : {
        "gt" : 搜索条件1, 
"lte" : 搜索条件2
      }
    }
  }
}

3.5多条件复合搜索

在一个请求体中,有多个搜索条件,就是复合搜索。如:搜索数据,条件为部门名称是Sales Department,员工年龄在20到26之间,部门员工姓名叫张三。上述条件中,部门名称为可选条件,员工年龄必须满足要求,部门员工姓名为可选要求。这种多条件搜索就是复合搜索。

代码语言:javascript
复制
GET 索引名/类型名/_search
{
  "query": {
    "bool": {
      "must": [ #数组中的多个条件必须同时满足
        {
          "range": {
            "字段名": {
              "lt": 条件
            }
          }
        }
      ],
      "must_not":[ #数组中的多个条件必须都不满足
        {
          "match": {
            "字段名": "条件"
          }
        },
        {
          "range": {
            "字段名": {
              "gte": "搜索条件"
            }
          }
        }
]
      "should": [# 数组中的多个条件有任意一个满足即可。
        {
          "match": {
            "字段名": "条件"
          }
        },
        {
          "range": {
            "字段名": {
              "gte": "搜索条件"
            }
          }
        }
      ]
    }
  }
}

3.6排序

在Elasticsearch的搜索中,默认是使用相关度分数实现排序的。可以通过搜索语法实现定制化排序。

代码语言:javascript
复制
GET 索引名/类型名/_search
{
  "query": {
    [搜索条件]
  },
  "sort": [
    {
      "字段名1": {
        "order": "asc"
      }
    },
    {
      "字段名2": {
        "order": "desc"
      }
    }
  ]
}

注意:在Elasticsearch中,如果使用text类型的字段作为排序依据,会有问题。Elasticsearch需要对text类型字段数据做分词处理。如果使用text类型字段做排序,Elasticsearch给出的排序结果未必友好,毕竟分词后,先使用哪一个单词做排序都是不合理的。所以Elasticsearch中默认情况下不允许使用text类型的字段做排序,如果需要使用字符串做结果排序,则可使用keyword类型字段作为排序依据,因为keyword字段不做分词处理。

3.7分页

DSL分页也是使用from和size实现的。

代码语言:javascript
复制
GET 索引名称/_search
{
  "query":{
    "match_all":{}
},
"from": 起始下标,
"size": 查询记录数
}

3.8highlight display

在搜索中,经常需要对搜索关键字做高亮显示,这个时候就可以使用highlight语法。

代码语言:javascript
复制
语法:
GET 索引名/_search
{
  "query": {
    "match": {
      "字段名": "条件"
    }
  },
  "highlight": {
    "fields": {
      "要高亮显示的字段名": {
        "fragment_size": 5, #每个分段长度,默认20
        "number_of_fragments": 1 #返回多少个分段,默认3
      }
    },
    "pre_tags": ["前缀"], 
    "post_tags": ["后缀"] 
  }
}
// 演示案例
GET test_search/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "dname": "Development department"
          }
        },
        {
          "match": {
            "gender": "男性"
          }
        }
      ]
    }
  },
  "highlight": {
    "fields": {
      "dname": {
        "fragment_size": 20,
        "number_of_fragments": 1
      },
      "gender": {
        "fragment_size": 20,
        "number_of_fragments": 1
      }
    },
    "pre_tags":["<span style='color:red'>"],
    "post_tags":["</span>"]
  }, 
  "from": 2,
  "size": 2
}
代码语言:javascript
复制
fragment_size:代表字段数据如果过长,则分段,每个片段数据长度为多少。长度不是字符数量,是Elasticsearch内部的数据长度计算方式。默认不对字段做分段。
number_of_fragments:代表搜索返回的高亮片段数量,默认情况下会将拆分后的所有片段都返回。
pre_tags:高亮前缀
post_tags:高亮后缀
很多搜索结果显示页面中都不会显示完整的数据,这样在数据过长的时候会导致页面效果不佳,都会按照某一个固定长度来显示搜索结果,所以fragment_size和number_of_fragments参数还是很常用的。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/02/15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Elasticsearch中的mapping问题
    • 1 mapping核心数据类型
      • 2 dynamic mapping对字段的类型分配
        • 3 查看索引mapping
          • 4 custom mapping
            • 4.1创建索引时指定mapping
        • Search 搜索详解
          • 2query string search
            • 2.1全搜索
            • 2.2multi index搜索
            • 2.3分页搜索
            • 2.4+/-搜索
            • 2.5排序
          • 3 query DSL
            • 3.1查询所有数据
            • 3.2match search(项目搜索功能使用此命令)
            • 3.3phrase search
            • 3.4range
            • 3.5多条件复合搜索
            • 3.6排序
            • 3.7分页
            • 3.8highlight display
        相关产品与服务
        Elasticsearch Service
        腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档