如何在含nested字段的Elasticsearch映射中仅统计根文档?
关于Elasticsearch嵌套字段下根文档聚合计数的问题
原始问题
我的Elasticsearch映射包含一个nested字段,根据文档说明,ES会将nested字段中的每个项扩展为独立文档,再加上根文档。但出于业务逻辑需求,我需要仅对根文档进行计数和查询,是否有实现方法?我了解到reverse_nested可能是解决方案,但使用它是否必须至少查询nested字段中的一个字段?
更新需求
我需要针对根对象按指定字段进行聚合计数,示例如下:
创建索引映射
PUT test { "mappings": { "properties": { "flag": "keyword", "topics": { "type": "nested" } } } }
批量插入文档
POST test/_bulk {"index":{"_index":"test" }} {"flag":"A", "topics":[ {"topic":"topic 1"}, {"topic":"topic 2"}], "_id": 1} {"index":{"_index":"test" }} {"flag":"A", "topics":[ {"topic":"topic 2"}, {"topic":"topic 3"}], "_id": 2} {"index":{"_index":"test" }} {"flag":"B", "topics":[ {"topic":"topic 1"}, {"topic":"topic 3"}], "_id": 3}
(注:原示例中第三个文档_id重复为2,此处修正为3避免冲突)
期望正确结果
按flag字段返回根文档计数:
{ "key": "A", "doc_count": 2 }, { "key": "B", "doc_count": 1 }
错误结果(需避免)
因nested字段展开导致的重复计数:
{ "key": "A", "doc_count": 6 }, { "key": "B", "doc_count": 3 }
解决方案
基础场景:直接统计根文档
如果不需要操作nested字段的内容,直接对根文档字段做聚合即可得到正确的根文档计数,根本无需涉及nested或reverse_nested操作。
针对你的示例需求,执行以下查询:
GET test/_search { "size": 0, "aggs": { "flag_count": { "terms": { "field": "flag" } } } }
该查询会直接统计每个flag对应的根文档数量,返回结果就是你期望的正确计数。
关于reverse_nested的说明
reverse_nested的作用是在nested聚合/查询的上下文内,切换回根文档上下文做聚合,它确实需要先进入nested上下文(即先执行nested查询或聚合)才能使用。但你的基础场景完全不需要用到它——只有当你需要先筛选nested字段的内容,同时统计对应根文档数量时,才需要它。
比如,如果你需要找出包含topic: "topic 1"的文档,再按flag统计这些根文档的数量,可以用以下两种方式:
方式1:nested查询 + 根字段聚合
GET test/_search { "size": 0, "query": { "nested": { "path": "topics", "query": { "term": { "topics.topic": "topic 1" } } } }, "aggs": { "flag_count": { "terms": { "field": "flag" } } } }
方式2:nested聚合内使用reverse_nested
GET test/_search { "size": 0, "aggs": { "topics_agg": { "nested": { "path": "topics" }, "aggs": { "topic_filter": { "term": { "topics.topic": "topic 1" }, "aggs": { "root_context": { "reverse_nested": {}, "aggs": { "flag_count": { "terms": { "field": "flag" } } } } } } } } } }
这两种方式都会返回符合条件的根文档计数,不会因nested字段展开而重复统计。
内容的提问来源于stack exchange,提问作者JLuis Estrada
相关产品推荐
相关产品推荐

