Elasticsearch非嵌套数组对象term查询无结果、match查询正常的问题
我在Elasticsearch的movies索引中存储了以下数据:
[ { "title": "The Matrix", "cast": [ { "title": "Keanu Reeves", "score": 76 }, { "firstName": "Laurence Fishburne", "score": 76 } ] }, { "title": "Wolf of wall street", "cast": [ { "title": "Leonardo DiCaprio", "score": 76 } ] } ]
注:我尚未设置nested映射,因为仅需对cast对象的单个属性进行查询。
当使用match查询时,可以返回对应数据:
GET /movies/_search { "query": { "bool": { "must": [ { "match": { "cast.title": "Keanu Reeves" } } ] } } }
但改用term查询时,却无法返回任何数据:
GET /movies/_search { "query": { "bool": { "must": [ { "term": { "cast.title": "Keanu Reeves" } } ] } } }
请问这是什么原因?
原因分析
核心问题出在字段的分词处理和match/term查询的本质区别上:
字段分词逻辑:
你没有指定cast.title的映射类型,Elasticsearch会默认将其识别为text类型,并用标准分词器处理。"Keanu Reeves"会被拆分成两个独立的词项:keanu和reeves,存储到倒排索引中。match查询的工作方式:
match查询会先对你输入的查询文本"Keanu Reeves"做同样的分词处理,拆成keanu和reeves,然后去倒排索引中匹配包含这些词项的文档,所以能找到对应结果。term查询的工作方式:
term查询是精确匹配,它会直接用你输入的完整字符串"Keanu Reeves"去倒排索引中查找完全一致的词项。但倒排索引里只有keanu和reeves这两个单独的词,不存在完整的"Keanu Reeves",所以匹配不到任何数据。
另外补充:你没设置nested映射的情况,不会导致这次查询失败(只有在需要关联查询同一个cast对象的多个属性时,扁平化的对象结构才会出问题),本次问题的核心还是分词逻辑和查询类型的差异。
如果想用term查询找到结果,可以改用cast.title.keyword字段(Elasticsearch默认会给text类型生成对应的keyword子字段,不分词,存储完整字符串),查询语句改成:
GET /movies/_search { "query": { "bool": { "must": [ { "term": { "cast.title.keyword": "Keanu Reeves" } } ] } } }
内容的提问来源于stack exchange,提问作者Uday Reddy

