Elasticsearch数组字段多条件查询无交集问题及嵌套查询咨询
问题原因
普通对象数组字段在Elasticsearch中会被扁平化处理,event.jobname和event.result会被拆分为两个独立的多值字段,而非关联的键值对。比如Andy的记录中,event.jobname包含job1、job2、job3,event.result包含bad、bad、good,所以你的查询条件event.jobname:job1和event.result:good会被分别匹配——只要文档中存在任意一个元素满足job1,且任意一个元素满足result:good,就会被命中。Andy的job3满足result:good,因此也被返回了。
解决方案
方案1:修改Mapping为Nested类型(推荐)
这是Elasticsearch处理对象数组的标准方式,能确保数组内每个对象的字段保持关联。
步骤1:更新索引Mapping
若已有数据需先迁移,重新创建索引并设置event为nested类型:
PUT index_name { "mappings": { "properties": { "name": { "type": "text" }, "event": { "type": "nested", "properties": { "jobname": { "type": "keyword" }, "result": { "type": "keyword" } } } } } }
步骤2:使用Nested Query查询
- 针对你之前的需求(找包含
jobname:job1且result:good的记录):
POST index_name/_search { "query": { "nested": { "path": "event", "query": { "bool": { "filter": [ { "term": { "event.jobname": "job1" } }, { "term": { "event.result": "good" } } ] } } } } }
- 针对你实际的需求(同时包含
jobname:job1,以及jobname:job2且result:bad的记录):
POST index_name/_search { "query": { "bool": { "must": [ { "nested": { "path": "event", "query": { "term": { "event.jobname": "job1" } } } }, { "nested": { "path": "event", "query": { "bool": { "filter": [ { "term": { "event.jobname": "job2" } }, { "term": { "event.result": "bad" } } ] } } } } ] } } }
方案2:使用Script Query(无需修改Mapping)
如果无法修改索引Mapping,可通过脚本遍历数组元素,检查关联键值对是否存在。
- 针对你之前的需求(job1且result:good):
POST index_name/_search { "query": { "bool": { "filter": [ { "script": { "script": """ ctx._source.event.stream().anyMatch(e -> e.jobname == 'job1' && e.result == 'good') """ } } ] } } }
- 针对你实际的需求(包含job1,且包含job2+result:bad):
POST index_name/_search { "query": { "bool": { "filter": [ { "script": { "script": """ ctx._source.event.stream().anyMatch(e -> e.jobname == 'job1') && ctx._source.event.stream().anyMatch(e -> e.jobname == 'job2' && e.result == 'bad') """ } } ] } } }
注意:Script Query性能远低于Nested Query,数据量较大时不推荐使用。
内容的提问来源于stack exchange,提问作者RN S
相关产品推荐
相关产品推荐

