Elasticsearch聚合查询如何同时获取top_hits字段与sum汇总值
解决方案
原生DSL实现(兼容ES 5.x)
不需要在top_hits中嵌套聚合,只需要将sum聚合与top_hits平级放在customer_id分组的子聚合层级即可,ES会在每个客户对应的分组桶中同时返回两类聚合结果,只需做简单的字段拼接就能得到目标输出格式,无额外性能损耗。
参考DSL如下:
GET kibana_sample_data_ecommerce/_search { "size": 0, "aggs": { "by_user_id": { "terms": { "field": "customer_id", "size": 100 // 可按需调整返回的客户数量,默认仅返回10条 }, "aggs": { "customer_info": { "top_hits": { "size": 1, "_source": {"includes": ["customer_full_name"]} } }, "total_spent": { "sum": { "field": "products.taxful_price" } } } } } }
返回的每个分组桶结构如下:
{ "key" : "27", "doc_count" : 348, "customer_info" : { "hits" : { "hits" : [ { "_source" : {"customer_full_name" : "Elyssa Underwood"} } ] } }, "total_spent" : { "value" : 1234.5678 } }
遍历所有分组桶,将total_spent的value值合并到top_hits返回的_source中,即可得到你需要的输出格式。
NEST客户端实现(C#)
参考代码如下:
var response = client.Search<object>(s => s .Index("kibana_sample_data_ecommerce") .Size(0) .Aggregations(a => a .Terms("by_user_id", t => t .Field("customer_id") .Size(100) .Aggregations(aa => aa .TopHits("customer_info", th => th .Size(1) .Source(src => src.Include(f => f.Field("customer_full_name"))) ) .Sum("total_spent", sum => sum .Field("products.taxful_price") ) ) ) ) ); // 结果处理示例 var result = new List<object>(); var userBuckets = response.Aggregations.Terms("by_user_id").Buckets; foreach (var bucket in userBuckets) { var customerHit = bucket.TopHits("customer_info").Hits<dynamic>().First(); customerHit.Source.total_spent = bucket.Sum("total_spent").Value; result.Add(customerHit); }
如果想要完全避免手动拼接结果,也可以使用scripted_metric聚合直接生成目标格式,但性能会比上述平级聚合方案差,非必要不推荐使用。
内容的提问来源于stack exchange,提问作者Ramiro Pellegrini
相关产品推荐
相关产品推荐

