在Elasticsearch嵌套类型中实现terms聚合内的指标聚合
Elasticsearch嵌套字段聚合问题解决
文档存储结构
Doc1:
{ "owner": "owner_1", "attributes" : [ { "name": "dump", "value": "xyz" }, { "name": "weight", "value": "150" } ] }
Doc2:
{ "owner": "owner_2", "attributes" : [ { "name": "dump", "value": "xyz" }, { "name": "weight", "value": "600" } ] }
Doc3:
{ "owner": "owner_3", "attributes" : [ { "name": "dump", "value": "abc" }, { "name": "weight", "value": "40" } ] }
字段说明
attributes为nested类型字段。
需求说明
- 筛选出
attributes字段中包含name为dump的文档; - 按
dump对应的value值(abc、xyz)进行terms聚合; - 计算每个
dump分组下所有文档的weight总和。
期望输出结果
{ ... "aggregations": { ... "buckets": [ { "key": "xyz", "doc_count": 2, "weight_sum": { "value": 750 } }, { "key": "abc", "doc_count": 1, "weight_sum": { "value": 40 } } ] } }
(注:原需求中xyz分组的weight总和应为150+600=750,已修正数值)
已尝试的查询及问题
原查询代码(已修正路径错误,原文档无doc层级):
{ "size": 0, "query": { "nested": { "path": "attributes", "query": { "bool": { "must": [ { "term": { "attributes.name.keyword": "dump" } } ] } } } }, "aggs": { "attributes": { "nested": { "path": "attributes" }, "aggs": { "NAME_BUCKET": { "filter": { "terms": { "attributes.name.keyword": [ "dump", "weight" ] } }, "aggs": { "VALUE_BUCKET": { "terms": { "field": "attributes.value.keyword", "size": 100 }, "aggs": { "weight": { "sum": { "script": { "lang": "painless", "source": """ if(doc['attributes.name.keyword'].value == "weight") { return Double.parseDouble(doc['attributes.value.keyword'].value); } return 0; """ } } } } } } } } } } }
得到的错误输出:
{ ..., ..., "buckets": [ { "key": "abc", "doc_count": 1, "weight": { "value": 0.0 } }, { "key": "xyz", "doc_count": 2, "weight": { "value": 0.0 } }, { "key": "150", "doc_count": 1, "weight": { "value": 150.0 } }, { "key": "40", "doc_count": 1, "weight": { "value": 40.0 } }, { "key": "600", "doc_count": 1, "weight": { "value": 600.0 } } ] }
问题核心:原聚合在nested条目层级直接混排dump和weight的value,无法关联同一文档内的dump与weight值,导致分组混乱、总和计算错误。
修正后的查询
{ "size": 0, "query": { "nested": { "path": "attributes", "query": { "term": { "attributes.name.keyword": "dump" } } } }, "aggs": { "dump_values": { "nested": { "path": "attributes" }, "aggs": { "filter_dump": { "filter": { "term": { "attributes.name.keyword": "dump" } }, "aggs": { "dump_value_groups": { "terms": { "field": "attributes.value.keyword", "size": 100 }, "aggs": { "back_to_root": { "reverse_nested": {}, "aggs": { "weight_sum": { "nested": { "path": "attributes" }, "aggs": { "filter_weight": { "filter": { "term": { "attributes.name.keyword": "weight" } }, "aggs": { "sum_weight": { "sum": { "script": "Double.parseDouble(doc['attributes.value.keyword'].value)" } } } } } } } } } } } } } } } }
逻辑说明
- 查询过滤:通过nested查询筛选出包含
name=dump的文档,确保仅处理符合条件的数据; - dump值分组:进入nested层级,过滤出
name=dump的条目并按value分组; - 关联weight计算:通过
reverse_nested回到根文档,再次进入nested层级过滤出name=weight的条目,计算该分组下所有文档的weight总和; - 结果对齐:每个dump value分组对应关联文档的weight总和,完全匹配需求。
修正后输出
{ "took": 2, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 3, "relation": "eq" }, "max_score": null, "hits": [] }, "aggregations": { "dump_values": { "doc_count": 6, "filter_dump": { "doc_count": 3, "dump_value_groups": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "xyz", "doc_count": 2, "back_to_root": { "doc_count": 2, "weight_sum": { "doc_count": 2, "filter_weight": { "doc_count": 2, "sum_weight": { "value": 750.0 } } } } }, { "key": "abc", "doc_count": 1, "back_to_root": { "doc_count": 1, "weight_sum": { "doc_count": 1, "filter_weight": { "doc_count": 1, "sum_weight": { "value": 40.0 } } } } } ] } } } } }
内容的提问来源于stack exchange,提问作者Kartik Chauhan
相关产品推荐
相关产品推荐

