Elasticsearch 6.8中match_phrase结合N-gram分词匹配'rm'失败问题
问题分析:为何N-gram分词后
match_phrase无法匹配到"rm" 首先得明确match_phrase的核心逻辑:它会先把查询文本用字段指定的分词器切成token序列,然后要求目标文档的分词结果里,必须包含这个完整的序列,而且token要按顺序严格连续出现(默认slop=0)——这里的"连续"指后续token的位置必须和前一个保持严格的顺序递进关系。
1. 先拆解查询词"rm"的分词结果
当你用match_phrase查"rm"时,Elasticsearch会用dbName字段的my_analyzer处理查询文本,基于你的N-gram配置(min_gram=1, max_gram=3),得到的token列表是:
["r", "rm", "m"]
每个token对应的起始位置(position):
"r"→ position 0"rm"→ position 0"m"→ position 1
2. 再看目标文档的分词细节
以文档1(dbName: "rm.rf")为例,用my_tokenizer分词后的完整token及对应position如下:
| Token | Position |
|---|---|
| "r" | 0 |
| "rm" | 0 |
| "rm." | 0 |
| "m" | 1 |
| "m." | 1 |
| "m.r" | 1 |
| "." | 2 |
| ".r" | 2 |
| ".rf" | 2 |
| "r" | 3 |
| "rf" | 3 |
| "f" | 4 |
3. 为什么match_phrase匹配失败?
match_phrase要求查询的token序列按顺序连续出现:
- 第一步找到
"r"(position 0)没问题 - 第二步找到紧跟的
"rm"(position 0)也满足 - 但第三步需要找到紧跟
"rm"的"m"(position 1),可文档里"rm"之后的下一个token是"rm."(position 0),不是"m",整个序列的连续性被打断,所以匹配失败。
4. 为何搜索".rf"能成功匹配?
同样分析查询词".rf"的分词结果:
[".", ".r", ".rf", "r", "rf", "f"]
对应的position:
"."→ position 0".r"→ position 0".rf"→ position 0"r"→ position 1"rf"→ position 1"f"→ position 2
而文档1的分词结果里,"."(position2)→ ".r"(position2)→ ".rf"(position2)是连续出现的,完全符合match_phrase的匹配规则,所以能成功命中文档1。
解决方案:如何匹配包含"rm"的文档?
如果只是想匹配包含"rm"这个token的文档,不需要严格的短语连续,推荐两种方式:
- 用
match查询:它会匹配任何包含查询分词结果中token的文档,不需要严格连续
GET /m8/table/_search { "query": { "bool": { "must": [ { "match": { "dbName": "rm" } } ] } } }
- 用
term查询:精确匹配"rm"这个token(注意:term查询不会对查询文本分词,直接匹配索引中的token)
GET /m8/table/_search { "query": { "bool": { "must": [ { "term": { "dbName": "rm" } } ] } } }
内容的提问来源于stack exchange,提问作者Rollsbean
相关产品推荐
相关产品推荐

