Elasticsearch如何实现匹配所有查询词且字段完全匹配的检索
Elasticsearch 任意顺序全词精确匹配实现方案
你的需求本质是同时满足两个匹配规则:
- 目标字段分词结果覆盖全部输入查询词,不限制词的顺序
- 目标字段分词结果不存在查询词以外的冗余内容
直接使用terms、普通match或者keyword精确匹配都无法同时满足两个规则,可通过「全词命中校验+分词数等值校验」的组合方案实现,适配你当前字段同时映射text+keyword的架构。
方案1:生产环境推荐(性能最优)
提前给目标text字段增加token_count类型的子字段,索引阶段自动预计算字段的分词总数,查询时直接做等值过滤,避免脚本计算的性能损耗。
步骤1:补充字段映射
在原有字段映射基础上添加分词计数字段,注意分词器必须和text主字段使用的分词器完全一致,以标准分词器standard为例:
{ "mappings": { "properties": { "title": { "type": "text", "analyzer": "standard", "fields": { "keyword": { "type": "keyword" }, "token_cnt": { "type": "token_count", "analyzer": "standard" } } } } } }
添加后重建索引,title.token_cnt会自动存储每个文档title字段的分词数量:
- 文档
"Jurassic Park"分词后共2个词,token_cnt值为2 - 文档
"Lost World: Jurassic Park"分词后共4个词,token_cnt值为4 - 文档
"Jurassic Park III"分词后共3个词,token_cnt值为3
步骤2:查询实现
查询前先用和字段一致的分词器对输入查询词做分词,得到分词后的总词数,比如输入Park Jurassic分词后得到2个词,再通过bool查询组合两个条件:
match查询设置operator: and,保证字段覆盖所有查询词,不限制顺序term查询校验分词数和输入查询词的分词数完全相等,排除有冗余内容的文档
{ "query": { "bool": { "must": [ { "match": { "title": { "query": "Park Jurassic", "operator": "and" } } }, { "term": { "title.token_cnt": 2 } } ] } } }
以上查询只会返回"Jurassic Park"这一条符合要求的文档。
方案2:轻量场景临时实现(无需改映射)
如果数据量不大、不想修改原有索引映射,可以用脚本查询直接读取text字段的分词数做校验,不需要额外预存字段:
{ "query": { "bool": { "must": [ { "match": { "title": { "query": "Park Jurassic", "operator": "and" } } }, { "script": { "script": { "source": "doc['title'].size() == params.query_token_num", "params": { "query_token_num": 2 } } } } ] } } }
注意:脚本中
doc['title'].size()直接读取Elasticsearch倒排索引中存储的分词计数,不需要实时跑分词逻辑,性能损耗在可接受范围内,但数据规模超过百万级时优先选择预存token_count的方案。
常见写法不生效原因说明
- 普通
terms查询:仅校验字段是否包含指定分词,不限制冗余分词存在,会返回所有包含查询词的文档 - 普通
match查询:即使设置operator: and,也仅保证所有查询词存在,同样无法过滤有冗余内容的文档 keyword精确匹配:要求字段值和输入字符串完全一致,词序、大小写、标点差异都会导致匹配失败,无法支持任意顺序匹配的要求
内容的提问来源于stack exchange,提问作者user3428426
相关产品推荐
相关产品推荐

