子聚合是什么
聚合可以嵌套:外层聚合负责分桶,内层聚合针对每个桶再做指标计算或继续分桶,形成两层甚至多层统计。最常见的形式是 terms 分桶后按 avg、sum 之类指标排序,用来回答「按某个维度排前 N」的问题,比如按国家看平均客单价最高的前五名。
基本信息
| 结构 | aggs 里再写 aggs,子聚合只作用于当前桶内的文档 |
|---|---|
| 按子聚合排序 | order: { "子聚合名": "desc" },也可用 _count、_key |
| 常见内层聚合 | avg、sum、max、min、percentiles、cardinality,或再嵌一层 terms |
| 结果合并 | 子聚合先在分片本地计算,再在协调节点合并 |
| 适用版本 | Elasticsearch 7.x / 8.x 语法一致 |
典型使用场景
- 按维度取 Top N:按桶内指标而不是文档数决定桶序
- 两层统计:先按国家分桶,再看每个国家的客单价水平
- 多级下钻:品类到商品的两层桶统计
- 桶内条件细分:内层用 filter 聚合只看某种状态的文档
- 配合 size: 0 只要统计结果,不返回文档本身以省带宽
嵌套聚合写法
嵌套聚合写法
GET /orders/_search
{
"size": 0,
"aggs": {
"by_country": {
"terms": { "field": "country", "size": 5, "order": { "avg_price": "desc" } },
"aggs": {
"avg_price": { "avg": { "field": "price" } },
"paid_only": { "filter": { "term": { "status": "paid" } },
"aggs": { "sum_qty": { "sum": { "field": "qty" } } } }
}
}
}
}
# 桶内再分桶:品类 -> 商品,桶数量按乘积增长
GET /orders/_search
{ "size": 0, "aggs": { "cat": { "terms": { "field": "category", "size": 10 },
"aggs": { "sku": { "terms": { "field": "sku", "size": 5 } } } } } }桶序写法读法
| 排序写法 | 含义 | 注意 |
|---|---|---|
| order: { "avg_price": "desc" } | 按桶内 avg_price 从大到小取桶 | 子聚合名拼错会直接报错 |
| order: { "_count": "desc" } | 按桶内文档数排序,即默认行为 | 不写 order 时就是这个效果 |
| order: { "_key": "asc" } | 按分桶键本身排序 | 仅对可排序的键类型有效 |
| order: { "paid_only>sum_qty": "desc" } | 按多层路径下的指标排序 | 路径用 > 连接,层级深易出错 |
terms 聚合默认只返回文档数最多的前十个桶,并且多分片下按各分片局部 Top N 合并,桶序按子聚合指标排序时结果可能出现偏差;需要精确遍历应改用 composite 聚合分页拉取。
结果里的 doc_count_error_upper_bound 大于 0 说明桶内计数可能存在误差,sum_other_doc_count 大于 0 说明还有桶未被返回;看统计口径是否完整,先检查这两个字段而不是直接看桶值。