ElasticSearch嵌套字段聚合如何为每个桶返回额外字段
可以直接实现,无需额外查询原始文档
完全可以在聚合分桶中获取到绑定的ID字段,利用现有结构的字段绑定关系,用极低的聚合开销就能实现需求。
核心逻辑
你的filter_data.string_facet是nested类型结构,每个子对象内的四个字段是一一绑定的:
- 同一个
facet-name对应的facet-name-id是固定唯一值 - 同一个
facet-value对应的facet-value-id也是固定唯一值
不需要用开销较高的top_hits类聚合,只要在对应分桶下添加针对ID字段的轻量terms聚合,因为值唯一,聚合仅会返回单个结果,完全没有多余的性能损耗。
修改后可直接运行的查询DSL
{ "query": { "bool": { "must": { "match_all": {} } } }, "track_total_hits": true, "from": 0, "size": 0, "aggs": { "strings": { "nested": { "path": "filter_data.string_facet" }, "aggs": { "names": { "terms": { "field": "filter_data.string_facet.facet-name" }, "aggs": { // 新增:获取当前facet-name绑定的唯一facet-name-id "facet_name_id": { "terms": { "field": "filter_data.string_facet.facet-name-id", "size": 1 } }, "values": { "terms": { "field": "filter_data.string_facet.facet-value" }, "aggs": { // 新增:获取当前facet-value绑定的唯一facet-value-id "facet_value_id": { "terms": { "field": "filter_data.string_facet.facet-value-id", "size": 1 } } } } } } } } } }
聚合返回结构说明
执行上述查询后,原有分桶结构会补充对应节点:
- 每个
names层级的分桶下,新增facet_name_id聚合节点,节点内仅存在1个桶,桶的key即为该facet对应的facet-name-id - 每个
values层级的分桶下,新增facet_value_id聚合节点,节点内仅存在1个桶,桶的key即为该facet值对应的facet-value-id
后续处理时直接从对应节点取值拼接即可,无需额外发起对原始文档的查询。
高版本优化方案(Elasticsearch 7.12+)
如果使用的是7.12及以上版本,可直接使用terms聚合的keyed_field参数,实现更扁平的返回结构,无需额外子聚合:
// 替换原有names层级的terms配置 "names": { "terms": { "field": "filter_data.string_facet.facet-name", "keyed_field": "filter_data.string_facet.facet-name-id" } } // 替换原有values层级的terms配置 "values": { "terms": { "field": "filter_data.string_facet.facet-value", "keyed_field": "filter_data.string_facet.facet-value-id" } }
该方式返回的分桶会直接携带关联的keyed_field值,处理逻辑更简单,性能也更优。
注意事项
- 因为你的数据结构中facet名和ID是强绑定关系,设置子terms聚合
size:1是完全安全的,不会取错值 - 如果存在脏数据导致绑定关系失效,可以将上述子聚合替换为
top_hits并设置size:1,直接从_source中提取对应字段,仅会带来小幅性能损耗 - 不要使用script聚合获取ID值,性能远低于直接使用已存储的字段做聚合
内容的提问来源于stack exchange,提问作者ianion
相关产品推荐
相关产品推荐

