Elasticsearch查询含images的文档问题(无需修改映射)
首先,咱们先理清你遇到的几个核心问题,再给出不用修改映射的解决方案:
为什么之前的查询不生效?
1. must_not + exists返回所有记录的原因
你的images字段是object类型,且所有子字段都设置了index: false——这意味着Elasticsearch不会为这个object字段创建任何索引条目。哪怕你的_source里有images字段(比如示例里的空数组"images": []),exists查询也无法检测到它的存在,因为它根本没被索引。所以must_not [exists]会把那些有images空数组的文档也包含进来,最终返回所有记录。
2. 脚本查询报错"文本字段未启用field data"的原因
你尝试的doc['images'].values.length或doc['images.url'].values.length都依赖于doc values,但你的images子字段都是index: false,Elasticsearch不会为这些字段生成doc values;同时images作为object类型,也无法通过doc直接获取数组长度,所以会触发报错。
不用修改映射的解决方案
既然不能改映射,咱们可以直接从原始文档的_source中读取数据进行判断,这种方式不需要依赖索引字段,完全绕过上述限制。
1. 查询存在非空images数组的文档
使用脚本直接检查_source里的images是否存在且长度大于0:
POST catalog/_search { "query": { "script": { "script": "ctx._source.images != null && ctx._source.images.length > 0" } } }
2. 查询无images(字段不存在或为空数组)的文档
同样通过脚本判断_source里的images要么不存在,要么是空数组:
POST catalog/_search { "query": { "script": { "script": "ctx._source.images == null || ctx._source.images.length == 0" } } }
补充说明
直接访问ctx._source的脚本查询虽然能解决问题,但性能上会略低于基于索引字段的查询(因为需要加载原始文档数据)。如果后续有大量这类查询需求,还是建议修改映射,比如给images字段添加一个type: boolean的子字段来标记是否非空,或者开启某个子字段的doc_values,但目前这个方案能满足你"无需修改映射"的要求。
内容的提问来源于stack exchange,提问作者Raheel

