1、概述
在 ES 中进行短语搜索的时候,为了防止跨值访问,ES 会在每个值之间设置间隙
,而这个间隙的默认大小为 100。而这个值也就是 position_increment_gap。
那么什么是跨值访问
呢?
2、match_phrase 短语搜索
首先我们要理解 match_phrase 的匹配逻辑,match_phase 的匹配需要遵循以下三个条件
match_phrase 会对搜索短语分词(误区)
目标文档需要包含短语分词结果中所有词项
目标文档中匹配的所有词项必须和搜索短语完全相同,切顺序也必须完全相同
目标文档中匹配的所有词项中不能有任何其他不匹配项。
比如,搜索短语:that's a good question
那么以下文档均不符合短语搜索的要求,(暂不考虑文档归一化问题,即语气词通用的情况)
yes or no, that’s a question 。
yes or no, that’s good a question
yes or no, that’s a difficult question
yes or no, that’s a difficult good question
短语搜索是对短语分词的,这一点是一个非常容易踩坑的误区,很多人对短语搜索的理解就是文档中包含完整的短语,岁然从搜素结果上看的确是这样的,但是匹配逻辑却不失这样的。这一点需要格外的注意
3、跨值访问
3.1 问题演示
假设我们的 es 集群中存储了以下索引
PUT position_increment_gap_index/_doc/1 { "mappings" : { "properties" : { "title" : { "type" : "text" // slop 默认 100 } } } }
为索引写入一条数据
POST /position_increment_gap_index/_doc/1 { "title" : ["elastic org cn", "www elastic co"] }
当我们对title
进行短语搜索的时候,如果符合短语搜索的要求,是可以正常搜索到结果的,比如搜索elastic org cn
GET position_increment_gap_index/_search { "query": { "match_phrase": { "title": { "query": "elastic org cn" } } } }
结果如下
注意
当我们搜索的短语跨越了多个值的时候,比如搜索短语为:org cn www elastic
GET position_increment_gap_index/_search { "query": { "match_phrase": { "title": { "query": "org cn www elastic" } } } }
此时是搜索不到任何数据的,如下图所示,
3.2 原因
因为 ES 为了防止短语跨多个值访问,在每个值之间设置了默认为 100 的 slot 间隔。目的就是为了避免跨值访问。
3.3 解决方案
如果我们希望短语搜索可以跨越多个值进行访问,可以配置 slot 的值只需大于等于配置的值(默认 100)即可。
比如:slop 配置 100 有数据
GET position_increment_gap_index/_search { "query": { "match_phrase": { "title": { "query": "org cn www elastic", "slop": 100 } } } }
结果如下:
3.4 position_increment_gap 参数
当然我们可以通过position_increment_gap
参数,人为的配置字段多个值 slop 的值。
下面分别配置了slop
默认 100,以及slop
为 0 和slop
为 10 的两个子字段。
PUT position_increment_gap_index { "mappings" : { "properties" : { "title" : { "type" : "text", // slop 默认 100 "fields" : { "slop_0" : { "type": "text", "position_increment_gap" : 0 }, "slop_10" : { "type": "text", "position_increment_gap" :10 } } } } } }
mapping 创建成功之后,再次写入 3.1 小节中的测试数据,然后对 slot_0 执行同样的查询,因为 slop 配配置为了 0,所以可以直接得出数据。
GET position_increment_gap_index/_search { "query": { "match_phrase": { "title.slop_0": { "query": "org cn www elastic" } } } }
同样,对 slop_10
进行跨值查询。需要设置指定 slop: 10 以上才有数据
GET position_increment_gap_index/_search { "query": { "match_phrase": { "title.slop_10": { "query": "org cn www elastic", "slop": 10 } } } }