1. ES倒排索引
当数据写入ES时,数据将会通过“分词”被切分为不同的term,ES将term与其对应的文档列表建立一种映射关系,这种结构就是倒排索引。如下图所示:
为了进一步提升索引的效率,ES在term的基础上利用term的前缀或者后缀构建了term index,用于对term本身进行索引,ES实际的索引结构如下图所示:
这样当我们去搜索某个关键词时,ES 首先根据它的前缀或者后缀迅速缩小关键词的在term dictionary中的范围,大大减少了磁盘IO的次数。
- 单词词典(Term Dictionary) :记录所有文档的单词,记录单词到倒排列表的关联关系;
- 倒排列表(Posting List)-记录了单词对应的文档,由倒排索引项组成;
- 倒排索引项(Posting):
- 文档ID
- 词频TF–该单词在文档中出现的次数,用于相关性评分;
- 位置(Position)-单词在文档中分词的位置。用于短语搜索(match phrase query)
- 偏移(Offset)-记录单词的开始结束位置,实现高亮显示。
Elasticsearch的JSON文档中的每个字段,都有自己的倒排索引。
可以指定对某些字段不做索引:
- 优点︰节省存储空间
- 缺点: 字段无法被搜索
2. 文档映射Mapping
Mapping类似数据库中的Schema的定义,作用如下:
- 定义索引中的字段的名称
- 定义字段的数据类型,例如字符串,数字,布尔等;
- 字段,倒排索引的相关配置(Analyzer)。
ES中Mapping映射可以分为动态映射和静态映射:
- 动态映射:在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段、类型、长度、主键等,最后才能基于表插入数据。而Elasticsearch中不需要定义Mapping映射(即关系型数据库的表、字段等),在文档写入Elasticsearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。
- 静态映射:静态映射是在Elasticsearch中也可以事先定义好映射,包含文档的各字段类型、分词器等,这种方式称之为静态映射。
动态映射(Dynamic Mapping)的机制,使得我们无需手动定义Mappings,Elasticsearch会自动根据文档信息,推算出字段的类型。但是有时候会推算的不对,例如地理位置信息。当类型如果设置不对时,会导致一些功能无法正常运行,例如Range查询。
- Dynamic Mapping类型自动识别:
✒️示例
#删除原索引
DELETE /user
#创建文档(ES根据数据类型, 会自动创建映射)
PUT /user/_doc/1
{
"name":"magic",
"age":32,
"address":"哈尔滨中央大街"
}
#获取文档映射
GET /user/_mapping
思考:能否后期更改Mapping的字段类型?
两方面考虑:
- 新增加字段
- dynamic设为true时,一旦有新增字段的文档写入,Mapping也同时被更新;
- dynamic设为false,Mapping不会被更新,新增字段的数据无法被索引,但是信息会出现在_source中;
- dynamic设置成strict(严格控制策略),文档写入失败,抛出异常。
true |
false |
strict |
|
文档可索引 |
yes |
yes |
no |
字段可索引 |
yes |
no |
no |
Mapping被更新 |
yes |
no |
no |
- 对已有字段,一旦已经有数据写入,就不再支持修改字段定义。
- Lucene实现的倒排索引,一旦生成后,就不允许修改;
- 如果希望改变字段类型,可以利用 reindex API,重建索引。
原因:
- 如果修改了字段的数据类型,会导致已被索引的数据无法被搜索;
- 但是如果是增加新的字段,就不会有这样的影响。
📝测试
PUT /user
{
"mappings": {
"dynamic": "strict",
"properties": {
"name": {
"type": "text"
},
"address": {
"type": "object",
"dynamic": "true"
}
}
}
}
# 插入文档报错,原因为age为新增字段,会抛出异常
PUT /user/_doc/1
{
"name":"fox",
"age":32,
"address":{
"province":"湖南",
"city":"长沙"
}
}
dynamic设置成strict,新增age字段导致文档插入失败。
修改dynamic后再次插入文档成功
#修改daynamic
PUT /user/_mapping
{
"dynamic":true
}
对已有字段的mapping修改
- 如果要推倒现有的映射,你得重新建立一个静态索引;
- 然后把之前索引里的数据导入到新的索引里
- 删除原创建的索引
- 为新索引起个别名,为原索引名。
2.1 常用Mapping参数配置
2.1.1 index
index,控制当前字段是否被索引,默认为true;如果设置为false,该字段不可被搜索。
DELETE /user
PUT /user
{
"mappings" : {
"properties" : {
"address" : {
"type" : "text",
"index": false
},
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
PUT /user/_doc/1
{
"name":"magic",
"address":"哈尔滨中央大街",
"age":30
}
GET /user
GET /user/_search
{
"query": {
"match": {
"address": "广州"
}
}
}
2.1.2 index options
index options有四种不同的基本配置,控制倒排索引记录的内容:
- docs : 记录doc id
- freqs:记录doc id 和term frequencies(词频)
- positions: 记录doc id / term frequencies / term position
- offsets: doc id / term frequencies / term posistion / character offsets
text类型默认记录postions,其他默认为 docs;记录内容越多,占用存储空间越大。
DELETE /user
PUT /user
{
"mappings" : {
"properties" : {
"address" : {
"type" : "text",
"index_options": "offsets"
},
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
2.1.3 null_value
需要对Null值进行搜索,只有keyword类型支持设计Null_Value。
DELETE /user
PUT /user
{
"mappings" : {
"properties" : {
"address" : {
"type" : "keyword",
"null_value": "NULL"
},
"age" : {
"type" : "long"
},
"name" : {
"type" : "text"
}
}
}
}
PUT /user/_doc/1
{
"name":"fox",
"age":32,
"address":null
}
GET /user/_search
{
"query": {
"match": {
"address": "NULL"
}
}
}
2.1.4 copy_to
将字段的数值拷贝到目标字段,满足一些特定的搜索需求;copy_to的目标字段不出现在_source中。
# 设置copy_to
DELETE /address
PUT /address
{
"mappings" : {
"properties" : {
"province" : {
"type" : "keyword",
"copy_to": "full_address"
},
"city" : {
"type" : "text",
"copy_to": "full_address"
}
}
},
"settings" : {
"index" : {
"analysis.analyzer.default.type": "ik_max_word"
}
}
}
PUT /address/_bulk
{ "index": { "_id": "1"} }
{"province": "湖南","city": "长沙"}
{ "index": { "_id": "2"} }
{"province": "湖南","city": "常德"}
{ "index": { "_id": "3"} }
{"province": "广东","city": "广州"}
{ "index": { "_id": "4"} }
{"province": "湖南","city": "邵阳"}
GET /address/_search
{
"query": {
"match": {
"full_address": {
"query": "湖南常德",
"operator": "and"
}
}
}
}
2.2 Index Template
Index Templates可以帮助你设定Mappings和Settings,并按照一定的规则,自动匹配到新创建的索引之上。
- 模版仅在一个索引被新创建时,才会产生作用。修改模版不会影响已创建的索引;
- 你可以设定多个索引模版,这些设置会被“merge”在一起;
- 你可以指定“order”的数值,控制“merging”的过程。
2.2.1 模板的创建
PUT /_template/template_default
{
"index_patterns": ["*"],
"order": 0,
"version": 1,
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
PUT /_template/template_test
{
"index_patterns": ["test*"], #匹配index的
"order": 1,
"settings": {
"number_of_shards": 2,
"number_of_replicas": 1
},
"mappings": {
"date_detection": false,
"numeric_detection": true
}
}
2.2.2 模板的工作方式
当一个索引被新创建时,配置信息的默认规则:
- 应用Elasticsearch默认的settings和mappings
- 应用order数值低的lndex Template中的设定
- 应用order高的Index Template中的设定,之前的设定会被覆盖;
- 应用创建索引时,用户所指定的Settings和Mappings,并覆盖之前模版中的设定。
2.3 Dynamic Template
Dynamic Tempate定义在某个索引的Mapping中。粒度更细,可以根据字段类型设置模板。
#Dynaminc Mapping 根据类型和字段名
DELETE my_index
PUT my_index/_doc/1
{
"firstName":"Ruan",
"isVIP":"true"
}
GET my_index/_mapping
DELETE my_index
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"strings_as_boolean": {
"match_mapping_type": "string",
"match":"is*",
"mapping": {
"type": "boolean"
}
}
},
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
#结合路径
PUT /my_test_index
{
"mappings": {
"dynamic_templates": [
{
"full_name":{
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping":{
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
PUT /my_test_index/_doc/1
{
"name":{
"first": "John",
"middle": "Winston",
"last": "Lennon"
}
}
GET /my_test_index/_search
{
"query": {
"match": {
"full_name": "John"
}
}
}
3. ES高级查询Query DSL
ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL(Domain Specified Language),Query DSL是利用Rest API传递JSON格式的请求体(RequestBody)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁。
Query DSL | Elasticsearch Guide [7.17] | Elastic
📰语法
GET /es_db/_doc/_search {json请求体数据}
#可以简化为下面写法
GET /es_db/_search {json请求体数据}
✒️示例
#无条件查询,默认返回10条数据
GET /es_db/_search
{
"query":{
"match_all":{}
}
}
3.1 查询所有match_all
使用match_all,默认只会返回10条数据(_search查询默认采用的是分页查询,每页记录数size的默认值为10);如果想显示更多数据,指定size。
GET /es_db/_search
等同于
GET /es_db/_search
{
"query":{
"match_all":{}
}
}
#在查询中过滤
#不查看源数据,仅查看元字段
{
"_source": false,
"query": {
...
}
}
#只看以obj.开头的字段
{
"_source": "obj.*",
"query": {
...
}
}
3.1.1 返回指定条数size
使用size,指定查询结果中返回指定条数(默认返回值10条)。
GET /es_db/_search
{
"query": {
"match_all": {}
},
"size": 100
}
思考: size可以无限增加吗?
- 测试
GET /es_db/_search
{
"query": {
"match_all": {}
},
"size": 20000
}
- 出现异常
异常原因:
- 查询结果的窗口太大,from + size的结果必须小于或等于10000,而当前查询结果的窗口为20000。
- 可以采用scroll api更高效的请求大量数据集。
- 查询结果的窗口的限制可以通过参数index.max_result_window进行设置。
PUT /es_db/_settings
{
"index.max_result_window" :"20000"
}
#修改现有所有的索引,但新增的索引,还是默认的10000。
PUT /_all/_settings
{
"index.max_result_window" :"20000"
}
#查看所有索引中的index.max_result_window值
GET /_all/_settings/index.max_result_window
注意
参数index.max_result_window主要用来限制单次查询满足查询条件的结果窗口的大小,窗口大小由from + size共同决定。不能简单理解成查询返回给调用方的数据量。这样做主要是为了限制内存的消耗。
比如:from为1000000,size为10,逻辑意义是从满足条件的数据中取1000000到(1000000 + 10)的记录。这时ES一定要先将(1000000 + 10)的记录(即result_window)加载到内存中,再进行分页取值的操作。尽管最后我们只取了10条数据返回给客户端,但ES进程执行查询操作的过程中确需要将(1000000 + 10)的记录都加载到内存中,可想而知对内存的消耗有多大。这也是ES中不推荐采用(from + size)方式进行深度分页的原因。
同理,from为0,size为1000000时,ES进程执行查询操作的过程中确需要将1000000 条记录都加载到内存中再返回给调用方,也会对ES内存造成很大压力。
3.1.2 分页查询form
from 关键字,用来指定起始返回位置,和size关键字连用可实现分页效果。
ET /es_db/_search
{
"query": {
"match_all": {}
},
"size": 5,
"from": 0
}
3.1.3 指定字段排序sort
注意:会让得分失效
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
]
}
#排序,分页
GET /es_db/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": "desc"
}
],
"from": 10,
"size": 5
}
3.1.4 返回指定字段_source
_source 关键字,是一个数组,在这个数组中指定展示哪些字段。
GET /es_db/_search
{
"query": {
"match_all": {}
},
"_source": ["name","address"]
}
3.2 全文检索
全文检索查询(Full Text Queries)和术语级别查询(Term-Level Queries)是 Elasticsearch 中搜索和检索数据的两种不同方法。全文检索查询指在基于相关性搜索和匹配文本数据。这些查询会对输入的文本进行分析,将其拆分为词项(单个单词),并执行诸如分词、词干处理和标准化等操作。Elasticsearch 中的一些全文检索查询示例包括 match、match_phrase 和 multi_match 查询。全文检索的关键特点:
- 对输入的文本进行分析,并根据分析后的词项进行搜索和匹配。全文检索查询会对输入的文本进行分析,将其拆分为词项,并基于这些词项进行搜索和匹配操作。
- 以相关性为基础进行搜索和匹配。全文检索查询使用相关性算法来确定文档与查询的匹配程度,并按照相关性进行排序。相关性可以基于词项的频率、权重和其他因素来计算。
- 全文检索查询适用于包含自由文本数据的字段,例如文档的内容、文章的正文或产品描述等。
3.2.1 match query
match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找,match支持以下参数:
- query : 指定匹配的值
- operator : 匹配条件类型
- and:条件分词后都要匹配
- or:条件分词后有一个匹配即可(默认)
- operator : 匹配条件类型
- minmum_should_match:最低匹配度,即条件在倒排索引中最低的匹配度。
# 模糊匹配 分词后"or"的效果
GET /es_db/_search
{
"query": {
"match": {
"address": "广州白云山公园"
}
}
}
# 分词后"and"的效果
GET /es_db/_search
{
"query": {
"match": {
"address":{
"query": "广州白云山公园",
"operator": "and"
}
}
}
}
在match中的应用: 当operator参数设置为or时,minnum_should_match参数用来控制匹配的分词的最少数量。
# 最少匹配广州,公园两个词
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "广州公园",
"minimum_should_match": 2
}
}
}
}
3.2.2 match_phrase
短语查询,match_phrase查询分析文本并根据分析的文本创建一个短语查询。match_phrase会将检索关键词分词。match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序必须相同,而且默认必须都是连续的。
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": "广州白云山"
}
}
}
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": "广州白云"
}
}
}
- 思考:为什么查询广州白云山有数据,广州白云没有数据?
- 分析原因:
先查看广州白云山公园分词结果,可以知道广州和白云不是相邻的词条,中间会隔一个白云山,而match_phrase匹配的是相邻的词条,所以查询广州白云山有结果,但查询广州白云没有结果。
POST _analyze
{
"analyzer":"ik_max_word",
"text":"广州白云山"
}
#结果
{
"tokens" : [
{
"token" : "广州",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "白云山",
"start_offset" : 2,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 1
},
{
"token" : "白云",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 2
},
{
"token" : "云山",
"start_offset" : 3,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 3
}
]
}
如何解决词条间隔的问题?可以借助slop参数,slop参数告诉match_phrase查询词条能够相隔多远时仍然将文档视为匹配。
#广州云山分词后相隔为2,可以匹配到结果
GET /es_db/_search
{
"query": {
"match_phrase": {
"address": {
"query": "广州云山",
"slop": 2
}
}
}
}
3.2.3 multi_match
多字段查询,可以根据字段类型,决定是否使用分词查询,得分最高的在前面。
GET /es_db/_search
{
"query": {
"multi_match": { #地址和名称中如果匹配到都能查询到
"query": "长沙张龙",
"fields": [
"address",
"name"
]
}
}
}
注意:字段类型分词,将查询条件分词之后进行查询,如果该字段不分词就会将查询条件作为整体进行查询。
3.2.4 query_string
允许我们在单个查询字符串中指定AND | OR | NOT条件,同时也和 multi_match query 一样,支持多字段搜索。和match类似,但是match需要指定字段名,query_string是在所有字段中搜索,范围更广泛。
注意:查询字段分词就将查询条件分词查询,查询字段不分词将查询条件不分词查询。
3.2.4.1 未指定字段查询
GET /es_db/_search
{
"query": {
"query_string": {
"query": "张三 OR 橘子洲"
}
}
}
3.2.4.2 指定单个字段查询
#Query String
GET /es_db/_search
{
"query": {
"query_string": {
"default_field": "address",
"query": "白云山 OR 橘子洲"
}
}
}
3.2.4.3 指定多个字段查询
GET /es_db/_search
{
"query": {
"query_string": {
"fields": ["name","address"],
"query": "张三 OR (广州 AND 王五)"
}
}
}
3.2.5 simple_query_string
类似query_string,但是会忽略错误的语法,同时只支持部分查询语法,不支持AND OR NOT,会当作字符串处理。支持部分逻辑:
- + 替代AND
- | 替代OR
- - 替代NOT
#simple_query_string 默认的operator是OR
GET /es_db/_search
{
"query": {
"simple_query_string": {
"fields": ["name","address"],
"query": "广州公园",
"default_operator": "AND"
}
}
}
GET /es_db/_search
{
"query": {
"simple_query_string": {
"fields": ["name","address"],
"query": "广州 + 公园"
}
}
}
3.3 术语级别查询
术语级别查询(Term-Level Queries)指的是搜索内容不经过文本分析直接用于文本匹配,这个过程类似于数据库的SQL查询,搜索的对象大多是索引的非text类型字段。Elasticsearch 中的一些术语级别查询示例包括 term、terms 和 range 查询。
3.3.1 关键词查询Term
Term用来使用关键词查询(精确匹配),还可以用来查询没有被进行分词的数据类型。Term是表达语意的最小单位,搜索和利用统计语言模型进行自然语言处理都需要处理Term。match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找,而term会直接对关键词进行查找。一般模糊查找的时候,多用match,而精确查找时可以使用term。
- ES中默认使用分词器为标准分词器(StandardAnalyzer),标准分词器对于英文单词分词,对于中文单字分词。
- 在ES的Mapping Type 中 keyword、date、integer、long、double、boolean这些类型不分词,只有text类型分词。
注意:最好不要在term查询的字段中使用text字段,因为text字段会被分词,这样做既没有意义,还很有可能什么也查不到。
# 对bool,日期,数字,结构化的文本可以利用term做精确匹配
# term 精确匹配
GET /es_db/_search
{
"query": {
"term": {
"age": {
"value": 28
}
}
}
}
# 思考: 查询广州白云是否有数据,为什么?
GET /es_db/_search
{
"query":{
"term": {
"address": {
"value": "广州白云"
}
}
}
}
# 采用term精确查询, 查询字段映射类型为keyword
GET /es_db/_search
{
"query":{
"term": {
"address.keyword": {
"value": "广州白云山公园"
}
}
}
}
在ES中,Term查询时对输入不做分词。会将输入作为一个整体,在倒排索引中查找准确的词项,并且使用相关度算分公式为每个包含该词项的文档进行相关度算分。
PUT /product/_bulk
{"index":{"_id":1}}
{"productId":"xxx123","productName":"iPhone"}
{"index":{"_id":2}}
{"productId":"xxx111","productName":"iPad"}
# 思考: 查询iPhone可以查到数据吗? 答:查不到,因为"iPhone"会被小写保存。
GET /product/_search
{
"query":{
"term": {
"productName": {
"value": "iPhone"
}
}
}
}
GET /product/_analyze
{
"analyzer":"standard",
"text":"iPhone"
}
# 对于英文,可以考虑建立索引时忽略大小写
PUT /product
{
"settings": {
"analysis": {
"normalizer": {
"es_normalizer": {
"filter": [
"lowercase",
"asciifolding"
],
"type": "custom"
}
}
}
},
"mappings": {
"properties": {
"productId": {
"type": "text"
},
"productName": {
"type": "keyword",
"normalizer": "es_normalizer",
"index": "true"
}
}
}
}
使用Term查询时,可以通过Constant Score将查询转换成一个Filtering,避免算分,并利用缓存,提高性能。
- 将Query转成Filter,忽略TF-IDF计算,避免相关性算分的开销;
- Filter可以有效利用缓存
GET /es_db/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"address.keyword": "广州白云山公园"
}
}
}
}
}
term处理多值字段时,term查询是包含,不是等于。
POST /employee/_bulk
{"index":{"_id":1}}
{"name":"小明","interest":["跑步","篮球"]}
{"index":{"_id":2}}
{"name":"小红","interest":["跳舞","画画"]}
{"index":{"_id":3}}
{"name":"小丽","interest":["跳舞","唱歌","跑步"]}
POST /employee/_search
{
"query": {
"term": {
"interest.keyword": {
"value": "跑步"
}
}
}
}
3.3.2 多术语查询Terms
Terms用于在指定字段上匹配多个词项(terms)。它会精确匹配指定字段中包含的任何一个词项。
POST /es_db/_search
{
"query": {
"terms": {
"remark.keyword": ["java assistant", "java architect"]
}
}
}
3.3.3 exists query
在Elasticsearch中可以使用exists进行查询,以判断文档中是否存在对应的字段。
#查询索引库中存在remarks字段的文档数据
GET /es_db/_search
{
"query": {
"exists":
{
"field": "remark"
}
}
}
3.3.4 多id查询ids
ids 关键字 : 值为数组类型,用来根据一组id获取多个对应的文档。
GET /es_db/_search
{
"query": {
"ids": {
"values": [1,2]
}
}
}
3.3.5 范围查询range
- range:范围关键字
- gte 大于等于
- lte 小于等于
- gt 大于
- lt 小于
- now 当前时间
POST /es_db/_search
{
"query": {
"range": {
"age": {
"gte": 25,
"lte": 28
}
}
}
}
3.3.6 日期range
DELETE /product
POST /product/_bulk
{"index":{"_id":1}}
{"price":100,"date":"2021-01-01","productId":"BJ-1293"}
{"index":{"_id":2}}
{"price":200,"date":"2022-01-01","productId":"HRB-5421"}
GET /product/_mapping
GET /product/_search
{
"query": {
"range": {
"date": {
"gte": "now-2y"
}
}
}
}
3.3.7 前缀查询prefix
它会对分词后的term进行前缀搜索。
- 它不会分析要搜索字符串,传入的前缀就是想要查找的前缀;
- 默认状态下,前缀查询不做相关度分数计算,它只是将所有匹配的文档返回,然后赋予所有相关分数值为1。它的行为更像是一个过滤器而不是查询。两者实际的区别就是过滤器是可以被缓存的,而前缀查询不行。
prefix的原理:需要遍历所有倒排索引,并比较每个term是否已所指定的前缀开头。
GET /es_db/_search
{
"query": {
"prefix": {
"address": {
"value": "广州"
}
}
}
}
3.3.8 通配符查询wildcard
通配符查询:工作原理和prefix相同,只不过它不是只比较开头,它能支持更为复杂的匹配模式。
GET /es_db/_search
{
"query": {
"wildcard": {
"address": {
"value": "*白*"
}
}
}
}
3.3.9 模糊查询fuzzy
在实际的搜索中,我们有时候会打错字,从而导致搜索不到。在Elasticsearch中,我们可以使用fuzziness属性来进行模糊查询,从而达到搜索有错别字的情形。fuzzy查询会用到两个很重要的参数:fuzziness、prefix_length
- fuzziness:表示输入的关键字通过几次操作可以转变成为ES库里面的对应field的字段
- 操作是指:新增一个字符,删除一个字符,修改一个字符,每次操作可以记做编辑距离为1;
- 如中文集团到中威集团编辑距离就是1,只需要修改一个字符;
- 该参数默认值为0,即不开启模糊查询;
- 如果fuzziness值在这里设置成2,会把编辑距离为2的东东集团也查出来。
- prefix_length:表示限制输入关键字和ES对应查询field的内容开头的第n个字符必须完全匹配,不允许错别字匹配;
- 如这里等于1,则表示开头的字必须匹配,不匹配则不返回
- 默认值也是0
- 加大prefix_length的值可以提高效率和准确率。
GET /es_db/_search
{
"query": {
"fuzzy": {
"address": {
"value": "白运山",
"fuzziness": 1
}
}
}
}
GET /es_db/_search
{
"query": {
"match": {
"address": {
"query": "广洲",
"fuzziness": 1
}
}
}
}
注意:fuzzy模糊查询最大模糊错误必须在0-2之间
- 搜索关键词长度为 2,不允许存在模糊;
- 搜索关键词长度为3-5,允许1次模糊;
- 搜索关键词长度大于5,允许最大2次模糊。
3.4 高亮highlight
highlight 关键字,可以让符合条件的文档中的关键词高亮。highlight相关属性:
- pre_tags 前缀标签
- post_tags 后缀标签
- tags_schema 设置为styled可以使用内置高亮样式
- require_field_match 多字段高亮需要设置为false
3.4.1 自定义高亮html标签
可以在highlight中使用pre_tags和post_tags
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"post_tags": ["</span>"],
"pre_tags": ["<span style='color:red'>"],
"fields": {
"*":{}
}
}
}
3.4.2 多字段高亮
GET /products/_search
{
"query": {
"term": {
"name": {
"value": "牛仔"
}
}
},
"highlight": {
"pre_tags": ["<font color='red'>"],
"post_tags": ["<font/>"],
"require_field_match": "false",
"fields": {
"name": {},
"desc": {}
}
}
}
3.5 bool query布尔查询
布尔查询可以按照布尔逻辑条件组织多条查询语句,只有符合整个布尔条件的文档才会被搜索出来。在布尔条件中,可以包含两种不同的上下文。
- 搜索上下文(query context):使用搜索上下文时,Elasticsearch需要计算每个文档与搜索条件的相关度得分,这个得分的计算需使用一套复杂的计算公式,有一定的性能开销,带文本分析的全文检索的查询语句很适合放在搜索上下文中。
- 过滤上下文(filter context):使用过滤上下文时,Elasticsearch只需要判断搜索条件跟文档数据是否匹配,例如使用Term query判断一个值是否跟搜索内容一致,使用Range query判断某数据是否位于某个区间等。过滤上下文的查询不需要进行相关度得分计算,还可以使用缓存加快响应速度,很多术语级查询语句都适合放在过滤上下文中。
布尔查询一共支持4种组合类型:
类型 |
说明 |
must |
可包含多个查询条件,每个条件均满足的文档才能被搜索到,每次查询需要计算相关度得分,属于搜索上下文。 |
should |
可包含多个查询条件,不存在must和fiter条件时,至少要满足多个查询条件中的一个,文档才能被搜索到,否则需满足的条件数量不受限制,匹配到的查询越多相关度越高,也属于搜索上下文。 |
filter |
可包含多个过滤条件,每个条件均满足的文档才能被搜索到,每个过滤条件不计算相关度得分,结果在一定条件下会被缓存, 属于过滤上下文。 |
must_not文章来源:https://www.toymoban.com/news/detail-808361.html |
可包含多个过滤条件,每个条件均不满足的文档才能被搜索到,每个过滤条件不计算相关度得分,结果在一定条件下会被缓存, 属于过滤上下文。文章来源地址https://www.toymoban.com/news/detail-808361.html |
- 示例
PUT /books
{
"settings": {
"number_of_replicas": 1,
"number_of_shards": 1
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"language": {
"type": "keyword"
},
"author": {
"type": "keyword"
},
"price": {
"type": "double"
},
"publish_time": {
"type": "date",
"format": "yyy-MM-dd"
},
"description": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
POST /_bulk
{"index":{"_index":"books","_id":"1"}}
{"id":"1", "title":"Java编程思想", "language":"java", "author":"Bruce Eckel", "price":70.20, "publish_time":"2007-10-01", "description":"Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。"}
{"index":{"_index":"books","_id":"2"}}
{"id":"2","title":"Java程序性能优化","language":"java","author":"葛一鸣","price":46.5,"publish_time":"2012-08-01","description":"让你的Java程序更快、更稳定。深入剖析软件设计层面、代码层面、JVM虚拟机层面的优化方法"}
{"index":{"_index":"books","_id":"3"}}
{"id":"3","title":"Python科学计算","language":"python","author":"张若愚","price":81.4,"publish_time":"2016-05-01","description":"零基础学python,光盘中作者独家整合开发winPython运行环境,涵盖了Python各个扩展库"}
{"index":{"_index":"books","_id":"4"}}
{"id":"4", "title":"Python基础教程", "language":"python", "author":"Helant", "price":54.50, "publish_time":"2014-03-01", "description":"经典的Python入门教程,层次鲜明,结构严谨,内容翔实"}
{"index":{"_index":"books","_id":"5"}}
{"id":"5","title":"JavaScript高级程序设计","language":"javascript","author":"Nicholas C. Zakas","price":66.4,"publish_time":"2012-10-01","description":"JavaScript技术经典名著"}
GET /books/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "java编程"
}
},{
"match": {
"description": "性能优化"
}
}
]
}
}
}
GET /books/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "java编程"
}
},{
"match": {
"description": "性能优化"
}
}
],
"minimum_should_match": 1
}
}
}
GET /books/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"language": "java"
}
},
{
"range": {
"publish_time": {
"gte": "2010-08-01"
}
}
}
]
}
}
}
到了这里,关于ElasticSearch高级查询语法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!