Elasticsearch按geo.city分组统计去重user_id问题排查
解决Elasticsearch按嵌套字段分组统计非嵌套字段去重计数问题
问题场景
索引结构片段:
... user_id => [ type => keyword ], geo => [ type => nested city => [ type => keyword ] ... ] ...
需求是按geo.city分组,统计每个城市对应的去重user_id数量,对应SQL逻辑:
select geo.city as user_city, count(distinct user_id) as users from `table` group by user_city order by users desc
尝试了以下聚合查询,但distinct_users的统计结果始终为0:
'aggs' => [ 'nested_geo' => [ 'nested' => [ 'path' => 'geo', ], 'aggs' => [ 'group_by_city' => [ 'terms' => [ 'field' => 'geo.city', ], 'aggs' => [ 'distinct_users' => [ 'cardinality' => [ 'field' => 'user_id', ], ], ], ], ], ], ],
问题原因
进入nested聚合的上下文后,只能访问嵌套文档(即geo字段下的内容)中的字段,而user_id是根级别字段,不属于嵌套文档的一部分,因此在嵌套上下文里直接统计user_id会找不到数据,返回0。
解决方案
使用reverse_nested聚合回到根文档上下文,之后再对user_id进行去重计数(cardinality)。修改后的聚合查询如下:
'aggs' => [ 'nested_geo' => [ 'nested' => [ 'path' => 'geo', ], 'aggs' => [ 'group_by_city' => [ 'terms' => [ 'field' => 'geo.city', 'order' => ['distinct_users' => 'desc'] // 按用户数倒序,匹配SQL逻辑 ], 'aggs' => [ 'back_to_root' => [ 'reverse_nested' => [], // 回到根文档上下文 'aggs' => [ 'distinct_users' => [ 'cardinality' => [ 'field' => 'user_id' ] ] ] ] ], ], ], ], ],
说明
reverse_nested聚合的作用是退出嵌套文档上下文,回到包含该嵌套字段的根文档中,此时就能正常访问根级别字段user_id。- 在
terms聚合中添加order参数,实现按用户数倒序排列,与原SQL的order by users desc逻辑一致。
内容的提问来源于stack exchange,提问作者Valen Tin
相关产品推荐
相关产品推荐

