- 首先,看下下面的例子,猜下两条查询能不能召回 doc1
PUT test_phrase { "mappings" : { "_doc" : { "properties" : { "body" : { "type" : "text", "analyzer" : "ik_max_word", "search_analyzer" : "ik_smart" } } } } } PUT test_phrase/_doc/1 { "body":"南京市长" } GET test_phrase/_search { "query": { "match_phrase": { "body": "南京市长" } } } GET test_phrase/_search { "query": { "match_phrase": { "body": "南京" } } } 复制代码
- 结果如下图,『南京市长』无法召回,『南京』可以召回 ![]( gw.alipayobjects.com/zos/antfinc… =300x600)
原因分析
- 那么为什么呢?首先看一下,两个分词器结果不一,所以直接怀疑是由于分词不一造成的查不到的问题
# GET test_phrase/_analyze # { # "text": ["南京市长"], # "analyzer": "ik_max_word" # } { "tokens" : [ { "token" : "南京", "start_offset" : 0, "end_offset" : 2, "type" : "CN_WORD", "position" : 0 }, { "token" : "南京市", "start_offset" : 0, "end_offset" : 3, "type" : "CN_WORD", "position" : 1 }, { "token" : "市长", "start_offset" : 2, "end_offset" : 4, "type" : "CN_WORD", "position" : 2 } ] } # GET test_phrase/_analyze # { # "text": ["南京市长"], # "analyzer": "ik_smart" # } { "tokens" : [ { "token" : "南京", "start_offset" : 0, "end_offset" : 2, "type" : "CN_WORD", "position" : 0 }, { "token" : "市长", "start_offset" : 2, "end_offset" : 4, "type" : "CN_WORD", "position" : 1 } ] } 复制代码
- 那么为什么会由于分词不一而造成问题呢?
- 整理源码,我们可以看到 Phrase 的整体流程如下
- 具体如下
org.elasticsearch.index.query.MatchPhraseQueryBuilder#doToQuery org.elasticsearch.index.search.MatchQuery#parse
- 其中
org.elasticsearch.index.search.MatchQuery#getAnalyzer
确定分词器,如果查询没指定 analyzer 的话,那么 phrase 就用 searchQuoteAnalyzer,如果没有 searchQuoteAnalyzer 则用 searchAnalyzer
-
org.apache.lucene.util.QueryBuilder#createFieldQuery
进行分词并判断有无 graph 和同义词,如果没有就用简单的 phrase 查询 -
org.apache.lucene.util.QueryBuilder#analyzePhrase
构建真实查询,确定每个词的 postion -
org.apache.lucene.search.PhraseWeight#getPhraseMatcher
召回倒排链,然后判断 slop,如果为0,则转为ExactPhraseMatcher -
org.apache.lucene.search.ExactPhraseMatcher#nextMatch
比较 position 是否相等
- 其中
临时解法
- 由上面第二步,可以看到,其实 ES 本身也提供了利用 searchQuoteAnalyzer 的解决方案。因此临时解法可以是让用户给 text 字段增加
search_quote_analyzer
参数, search_quote_analyzer 官方文档 - 另外如果是单场景可以在查询时指定 analyzer 或者 querystring 里的 quote_analyzer
解决思路&难点
- 但是让用户修改并不优雅,因此我们还是希望可以寻求在引擎层解决的方案。但是目前尚未找到一个较好方案,暂时记录下思路,以后再做补充
- 由上面分析可知,这个问题的本质是 PhraseQuery 以 postion 位置连续性确定是否为短句,而由于写入时和查询时不同分词器,position不一致。
- 因此,有两个思路,但都有些难点,也希望抛砖引玉,大家能指导一下
多重 Position
- 思路: 修改 position 生成逻辑, 使得查询和写入时一致。 比如
ik_max_word
模式下有三种切分方式,就分别标记 position,而不是原来的混标,这样就可以保证 smart 也是 max 的一个子集 - 以『南京市长江大桥维修』为例
-
目前混标方案:
南京 南京市 市长 长江 长江大桥 大桥 维修 0 1 2 3 4 5 6 -
独立标注方案:
南京 南京市 市长 长江 长江大桥 大桥 维修 0 - 1 2 - 3 4 0 - 1 - 2 - 3 - 0 - 1 - 2 3 - 0 - - 1 - 2
-
- 难点:由上例子可以看出,这种方案虽然可以保证 position 的一致性,但是一旦有歧义词,则会造成后继词位置全不一样,会造成大量数据膨胀。如使用此方法,则需要找到一种快速记录查找多重 position 的方法
以上所述就是小编给大家介绍的《【踩坑分析】Elasticsearch 中文 PhraseQuery 无法精确匹配问题分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
A=B
Marko Petkovsek、Herbert S. Wilf、Doron Zeilberger / AK Peters, Ltd. / 1996-01 / USD 49.00
At some point, this book describes methods of solving the problem raised by Donald E. Knuth in the classical book "The Art of Computer Programming, Volume 1: Fundamental Algorithms". The main purpo......一起来看看 《A=B》 这本书的介绍吧!
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
SHA 加密
SHA 加密工具