Elasticsearch 6如何过滤文档对象数组并移除不匹配项
在Elasticsearch 6.0中过滤Nested数组并返回主文档过滤结果
Elasticsearch 6.0里,nested类型的数组是独立存储的,主文档的_source默认会保留原始数据,所以单纯用inner_hits只能拿到过滤后的子集,但主文档的数组还是完整的。要让主文档直接返回过滤后的数组项,有两种可行的实现方式:
方法一:用脚本字段生成过滤后的数组
通过script_fields自定义一个字段,用Painless脚本遍历原始数组,筛选出符合条件的项(无权限限制或匹配学生ID)。示例查询如下:
{ "query": { "nested": { "path": "basicPageBodyParagraphs", "query": { "bool": { "should": [ { "bool": { "must_not": { "exists": { "field": "basicPageBodyParagraphs.paragraphAccessRoles" } } } }, { "term": { "basicPageBodyParagraphs.paragraphAccessRoles": "student_123" } } ] } } } }, "script_fields": { "filtered_basicPageBodyParagraphs": { "script": { "lang": "painless", "source": """ def filtered = []; for (item in params._source.basicPageBodyParagraphs) { if (item.paragraphAccessRoles == null || item.paragraphAccessRoles == params.studentId) { filtered.add(item); } } return filtered; """, "params": { "studentId": "student_123" } } } }, "_source": ["_id"] // 可选,只返回必要字段,避免重复返回原始数组 }
返回结果中,filtered_basicPageBodyParagraphs字段就是过滤后的数组内容。
方法二:用脚本化_source修改返回的原始数据
如果希望直接修改_source里的数组内容,可以使用_source的脚本参数。注意需要在Elasticsearch配置文件elasticsearch.yml中开启inline脚本支持:script.inline: true、script.stored: true。示例查询:
{ "query": { "nested": { "path": "basicPageBodyParagraphs", "query": { "bool": { "should": [ { "bool": { "must_not": { "exists": { "field": "basicPageBodyParagraphs.paragraphAccessRoles" } } } }, { "term": { "basicPageBodyParagraphs.paragraphAccessRoles": "student_123" } } ] } } } }, "_source": { "script": { "lang": "painless", "source": """ def filtered = []; for (item in ctx._source.basicPageBodyParagraphs) { if (item.paragraphAccessRoles == null || item.paragraphAccessRoles == params.studentId) { filtered.add(item); } } ctx._source.basicPageBodyParagraphs = filtered; return ctx._source; """, "params": { "studentId": "student_123" } } } }
这种方式会直接修改返回的_source内容,把原始数组替换成过滤后的结果,但不会改变索引中存储的原始文档。
注意事项
- 两种方法都依赖Painless脚本,确保集群已开启脚本支持;
- 脚本字段方式不会修改原始
_source,适合需要同时保留原始数据和过滤结果的场景;脚本化_source方式更贴合你“主文档直接返回过滤数组”的需求; - 因为nested类型的存储特性,无法通过单纯的查询条件自动过滤主文档数组,必须借助脚本实现。
内容的提问来源于stack exchange,提问作者Jarede
相关产品推荐
相关产品推荐

