中 进阶
ES聚合查询#
一句话答案#
ES 聚合分 Bucket(分桶/分组)、Metric(指标计算)、Pipeline(二次计算)三类,可嵌套组合实现复杂数据分析;底层基于 doc_values 列式存储实现高效聚合,类似数据库的 GROUP BY + 聚合函数。
核心要点
聚合分类#
| 类型 | 作用 | 类比 SQL |
|---|---|---|
| Bucket | 按条件分桶 | GROUP BY |
| Metric | 计算指标 | SUM/AVG/MAX |
| Pipeline | 对聚合结果再计算 | 子查询/窗口函数 |
Bucket 聚合(分桶)#
// 按品牌分桶
{
"aggs": {
"brand_buckets": {
"terms": { "field": "brand", "size": 10 }
}
}
}
// 按价格区间分桶
{
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "to": 100 },
{ "from": 100, "to": 500 },
{ "from": 500 }
]
}
}
}
}
// 按日期直方图
{
"aggs": {
"monthly_sales": {
"date_histogram": {
"field": "created_at",
"calendar_interval": "month"
}
}
}
}jsonMetric 聚合(指标)#
{
"aggs": {
"avg_price": { "avg": { "field": "price" } },
"max_price": { "max": { "field": "price" } },
"total_sales": { "sum": { "field": "sales_count" } },
"price_stats": { "stats": { "field": "price" } },
"unique_brands": { "cardinality": { "field": "brand" } }
}
}json嵌套聚合#
// 每个品牌的平均价格(Bucket + Metric 嵌套)
{
"size": 0,
"aggs": {
"by_brand": {
"terms": { "field": "brand", "size": 10 },
"aggs": {
"avg_price": { "avg": { "field": "price" } },
"top_products": {
"top_hits": { "size": 3, "_source": ["name", "price"] }
}
}
}
}
}jsonPipeline 聚合#
// 每月销售额的环比增长率
{
"aggs": {
"monthly": {
"date_histogram": { "field": "date", "calendar_interval": "month" },
"aggs": {
"total_sales": { "sum": { "field": "amount" } }
}
},
"mom_growth": {
"derivative": { "buckets_path": "monthly>total_sales" }
}
}
}jsonDoc Values(聚合性能基础)#
倒排索引:词项 → 文档列表(适合搜索)
Doc Values:文档 → 字段值(适合排序/聚合)
存储方式:列式存储(类似 Parquet)
Doc1.price = 99
Doc2.price = 199
Doc3.price = 299
特点:
- 默认开启(除 text 类型外)
- 存在磁盘,通过 OS Page Cache 加速
- 不需要额外内存(对比 fielddata 需要大量 JVM 堆内存)plaintext聚合性能优化#
| 问题 | 方案 |
|---|---|
| 聚合太慢 | 加 filter 缩小聚合范围 |
| 高基数 terms | 用 composite 分页聚合 |
| 精确去重太慢 | cardinality 用 HyperLogLog(近似) |
| 全量聚合 | 预聚合(Rollup / Transform) |
面试回答(2分钟版)
ES 聚合分三类:Bucket 聚合按条件分桶(类似 GROUP BY),比如按品牌、按价格区间、按月份分桶;Metric 聚合在桶内做计算(avg/sum/max/cardinality);Pipeline 聚合对聚合结果再计算(如环比增长率)。三者可以嵌套组合,比如”每个品牌的平均价格+top3商品”就是 terms → avg + top_hits 嵌套。性能基础是 doc_values 列式存储——和倒排索引互补,倒排索引按词项查文档(搜索),doc_values 按文档取字段值(排序/聚合)。优化方面:加 filter 缩小聚合范围、高基数字段用 composite 分页、精确去重用 cardinality(底层 HyperLogLog 有约 0.5% 误差)。
追问与易错
追问方向:
- “text 字段能聚合吗?”→ 不能直接聚合(无 doc_values),需要开 fielddata(吃内存)或用 .keyword 子字段
- “cardinality 精确吗?”→ 底层 HyperLogLog,有约 0.5% 误差,真需要精确用 script
- “聚合和 SQL GROUP BY 区别?”→ ES 聚合可以多层嵌套、支持 Pipeline、实时分布式计算
易错点:
- ❌ “聚合结果是精确的”——terms 聚合在分布式场景下有精度问题(每个 Shard 各自取 Top-N 再合并)
- ❌ “size:0 不需要”——聚合时设 size:0 跳过 hits 返回,否则既查文档又做聚合
- ❌ “聚合能代替 OLAP”——ES 聚合适合实时简单分析,复杂 BI 分析用 ClickHouse/Doris