Elasticsearch 近似匹配
时间:2017-12-15 17:19:09
参考:
环境:
- 系统版本:Win10 64位
- Elasticsearch版本:6.0.0
近似匹配#
对于:
- Sue ate the alligator.
- The alligator ate Sue.
- Sue never goes anywhere without her alligator-skin purse.
用 match
搜索 sue alligator
,上面三个文档都会得到匹配,但却不能确定这两个词是否至来自于一种语境,甚至不能确定是否来自同一段落。想要语义更接近的数据有更高的相关度,这是我们就可以使用 短语匹配
或者 近似匹配
。
数据构造#
-
数据如下。
# 如果有删除 DELETE my_index # 设置主分区数目 PUT /my_index { "settings": { "number_of_shards": 1 }} # 插入数据 POST /my_index/my_type/_bulk { "index": { "_id": 1 }} { "title": "The quick brown fox" } { "index": { "_id": 2 }} { "title": "The quick brown fox jumps over the lazy dog" } { "index": { "_id": 3 }} { "title": "The quick brown fox jumps over the quick dog" } { "index": { "_id": 4 }} { "title": "Brown fox brown dog" }
短语查询#
-
match_phrase
是短语查询,匹配包含指定短语的文档。下面的例子匹配文档里有quick brown fox
三个单词相连的文档,如果删除fox
就不会匹配到任何数据。 -
match_phrase
查询,添加slop
灵活度参数,意思是在把要查询的词条移动灵活度指定的次数之内,如果可以匹配,也视为文档匹配。每个查询参数里面的每个单词都可以前移或后移。如下面的查询只会匹配title
是The quick brown fox jumps over the quick dog
的文档。GET /my_index/my_type/_search { "query": { "match_phrase": { "title": { "query": "quick jumps quick", "slop": 4 } } } }
官网的示例图:
为了使查询 fox quick 匹配我们的文档, 我们需要 slop 的值为 3:
-
position_increment_gap
参数指定同一个字段内包含多个数据(数组)时,在对字段创建倒排索引时,数组里面两个相邻元素的位置差,需要在创建索引前指定。 -
通过设置较大的
slop
值,可以使单词邻近的文档有更高的评分。 -
把邻近查询用来提高文档的相关度。由于邻近查询要求所有的字段都匹配才算匹配,可以把邻近查询放在should语句里面,用作提高评分,用 match 查询作为主查询,尽可能多的匹配文档。
-
rescore
结果集重新打分,通过match查询,查到对应的文档。然后对查询结果进行重打分,可以指定每个分片重打分文档的最大数量,可以避免上面那个例子里面使用should对所有匹配结果进行重打分的行为,提高查询效率。 -
寻找相关词,把两个相连的单词或者多个相连的单词作为索引。比如
Sue ate the alligator
对应的索引是["sue ate", "ate the", "the alligator"]
。具体步骤如下:- 如果索引里面已经存在数据需要删除索引,之后创建自定义的自定义的词汇单元过滤器。
PUT /my_index { "settings": { "number_of_shards": 1, "analysis": { "filter": { "my_shingle_filter": { "type": "shingle", "min_shingle_size": 2, "max_shingle_size": 2, "output_unigrams": false } }, "analyzer": { "my_shingle_analyzer": { "type": "custom", "tokenizer": "standard", "filter": [ "lowercase", "my_shingle_filter" ] } } } } }
-
上面的自定义词汇单元过滤器中
"output_unigrams": false
表示这个这个索引里面不会包含单个的单词,这样我们就需要多字段来表示来分别表示多单词的索引
和一个单词的索引
。例子如下:创建多字段:
PUT /my_index/_mapping/my_type { "my_type": { "properties": { "title": { "type": "text", "fields": { "shingles": { "type": "text", "analyzer": "my_shingle_analyzer" } } } } } }
初始化数据:
POST /my_index/my_type/_bulk { "index": { "_id": 1 }} { "title": "Sue ate the alligator" } { "index": { "_id": 2 }} { "title": "The alligator ate Sue" } { "index": { "_id": 3 }} { "title": "Sue never goes anywhere without her alligator skin purse" }
进行查询,会发现第二个查询包含
The alligator ate Sue
的文档有较高的评分:查询一:
查询二: