Elasticsearch统计嵌套数组内层元素总数量(含重复)实现方法
你当前得到的计数不符合预期,是因为Elasticsearch对普通Object类型的数组默认做拍平存储,不会保留数组内各个对象的边界。比如你第二个文档中inner数组有两个John和一个James,存储时inner.name会被处理为去重后的["John", "James"],普通terms聚合统计的是包含该值的父文档数量,两个父文档都包含John,所以计数为2。
以下是两个适配你需求的可选方案:
方案1:使用Nested类型(改动最小)
首先调整索引mapping,将inner字段设置为nested类型,该类型会保留数组内每个对象的独立边界:
PUT 你的索引名/_mapping { "properties": { "inner": { "type": "nested" } } }
重新写入数据后,使用nested聚合搭配terms即可得到正确计数:
{ "size": 0, "aggs": { "inner_docs": { "nested": { "path": "inner" }, "aggs": { "name_count": { "terms": { "field": "inner.name.keyword", "size": 10 } } } } } }
返回结果中aggregations.inner_docs.name_count.buckets就是你需要的统计值。现在7.3以上版本的Kibana已经原生支持nested字段的聚合操作,在Lens、常规可视化面板中都可以直接选择nested字段做统计,兼容问题已经不大。
方案2:平铺文档结构(Kibana兼容性最优)
如果完全不想接触nested的使用限制,可以直接在数据写入时将每个inner对象拆分为独立的顶层文档,结构调整为:
[ {"profile": "123", "name": "John"}, {"profile": "456", "name": "John"}, {"profile": "456", "name": "John"}, {"profile": "456", "name": "James"} ]
调整后你原来的聚合语句直接修改字段为name即可得到正确结果,且所有Kibana功能都可以直接使用,没有任何兼容问题,是维护成本最低的方案。
内容的提问来源于stack exchange,提问作者Pedro Kehl
相关产品推荐
相关产品推荐

