导语:如果说全文检索是 ElasticSearch 的"看家本领",那么聚合查询就是它的"数据大脑"。从电商平台的销售报表,到日志系统的异常监控,再到实时大屏的数据看板------聚合查询是让海量数据"开口说话"的关键能力。本章将从核心概念出发,逐步深入到嵌套聚合、排序优化等高级场景,帮你彻底掌握 ElasticSearch 的数据分析能力。
一、聚合查询核心概念:桶聚合与指标聚合
在 ElasticSearch 中,聚合(Aggregation)是对数据进行分组统计的核心机制。它的设计灵感来自 SQL 中的 GROUP BY + 聚合函数,但能力远超 SQL。
1.1 为什么要学聚合?
先看一个真实场景:
你负责一个电商平台的搜索服务。运营同学找到你:
- "帮我统计各品类的月销售额"
- "用户下单金额的分布情况如何?"
- "哪个价格区间的商品转化率最高?"
这些需求,本质上都是聚合查询。没有聚合,ElasticSearch 只是一个搜索引擎;有了聚合,它就是一个强大的实时分析引擎。
1.2 聚合的两大核心类型
ElasticSearch 将聚合分为两大类,理解它们的区别是掌握聚合的第一步:
(1)桶聚合(Bucket Aggregation)------"把数据分到不同的桶里"
桶聚合的作用类似于 SQL 的 GROUP BY,它根据某个条件将文档划分到不同的"桶"(Bucket)中,每个桶包含一组满足条件的文档。
以"商品品类"为例:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 数码产品 │ │ 服饰鞋包 │ │ 食品饮料 │ │ 家居家装 │
│ (桶A) │ │ (桶B) │ │ (桶C) │ │ (桶D) │
│ 1250条 │ │ 3420条 │ │ 890条 │ │ 2100条 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
(2)指标聚合(Metric Aggregation)------"对桶里的数据做计算"
指标聚合对一组文档的数值字段进行数学运算,计算出一个或多个指标值。它类似于 SQL 中的 SUM()、AVG()、COUNT(DISTINCT) 等聚合函数。
对"数码产品"这个桶做指标聚合:
数码产品桶
┌─────────────────────────────────┐
│ SUM(销售额) = ¥1,250,000 │
│ AVG(单价) = ¥2,350 │
│ MAX(单价) = ¥12,999 │
│ MIN(单价) = ¥29 │
└─────────────────────────────────┘
1.3 聚合查询的基本语法
聚合查询嵌套在查询请求的 aggs(或 aggregations)字段中:
json
GET /products/_search
{
"size": 0,
"aggs": {
"聚合名称": {
"聚合类型": {
"字段配置": "值"
}
}
}
}
关键参数说明:
| 参数 | 说明 |
|---|---|
size: 0 |
不返回原始文档,只返回聚合结果(推荐做法,减少内存消耗) |
aggs |
聚合查询的顶层关键字,与 aggregations 等价 |
聚合名称 |
自定义名称,用于在结果中标识该聚合 |
聚合类型 |
桶聚合或指标聚合的具体类型(如 terms、sum 等) |
1.4 管道聚合(Pipeline Aggregation)
除了桶聚合和指标聚合,还有一种特殊的聚合类型------管道聚合。它的输入是其他聚合的输出结果,而非原始文档。常见用法包括:
- 衍生桶聚合:对现有桶进一步计算
- 衍生指标聚合:对指标结果做二次计算
- 移动平均:计算时间序列的移动平均值
本章重点讲解桶聚合和指标聚合,管道聚合将在后续章节单独展开。
二、常用指标聚合:求和、平均值、最大值、最小值、去重计数
指标聚合是最基础也是最常用的聚合类型。我们以一个电商订单索引为例进行讲解。
2.1 准备测试数据
首先创建一个订单索引并插入测试数据:
json
# 创建索引映射
PUT /orders
{
"mappings": {
"properties": {
"order_id": { "type": "keyword" },
"user_id": { "type": "keyword" },
"category": { "type": "keyword" },
"product_name": { "type": "keyword" },
"price": { "type": "double" },
"quantity": { "type": "integer" },
"status": { "type": "keyword" },
"order_date": { "type": "date", "format": "yyyy-MM-dd" }
}
}
}
# 批量插入数据(bulk)
POST /orders/_bulk
{"index":{"_id":"1"}}
{"order_id":"ORD001","user_id":"U001","category":"数码","product_name":"iPhone 15","price":7999,"quantity":1,"status":"已完成","order_date":"2024-03-01"}
{"index":{"_id":"2"}}
{"order_id":"ORD002","user_id":"U002","category":"服饰","product_name":"春季外套","price":399,"quantity":2,"status":"已完成","order_date":"2024-03-02"}
{"index":{"_id":"3"}}
{"order_id":"ORD003","user_id":"U001","category":"数码","product_name":"AirPods Pro","price":1899,"quantity":1,"status":"已完成","order_date":"2024-03-03"}
{"index":{"_id":"4"}}
{"order_id":"ORD004","user_id":"U003","category":"食品","product_name":"有机坚果礼盒","price":168,"quantity":3,"status":"已发货","order_date":"2024-03-04"}
{"index":{"_id":"5"}}
{"order_id":"ORD005","user_id":"U002","category":"家居","product_name":"智能台灯","price":259,"quantity":1,"status":"已完成","order_date":"2024-03-05"}
{"index":{"_id":"6"}}
{"order_id":"ORD006","user_id":"U004","category":"数码","product_name":"iPad Air","price":4799,"quantity":1,"status":"已取消","order_date":"2024-03-06"}
{"index":{"_id":"7"}}
{"order_id":"ORD007","user_id":"U003","category":"服饰","product_name":"运动鞋","price":599,"quantity":1,"status":"已完成","order_date":"2024-03-07"}
{"index":{"_id":"8"}}
{"order_id":"ORD008","user_id":"U001","category":"食品","product_name":"进口红酒","price":328,"quantity":2,"status":"已完成","order_date":"2024-03-08"}
{"index":{"_id":"9"}}
{"order_id":"ORD009","user_id":"U005","category":"数码","product_name":"机械键盘","price":699,"quantity":1,"status":"已完成","order_date":"2024-03-09"}
{"index":{"_id":"10"}}
{"order_id":"ORD010","user_id":"U004","category":"家居","product_name":"空气净化器","price":1899,"quantity":1,"status":"已发货","order_date":"2024-03-10"}
2.2 Sum(求和)
计算某个数值字段的总和,最经典的指标聚合。
json
GET /orders/_search
{
"size": 0,
"aggs": {
"total_revenue": {
"sum": {
"field": "price"
}
}
}
}
返回结果:
json
{
"aggregations": {
"total_revenue": {
"value": 19036.0
}
}
}
实战技巧 :计算订单总金额时,通常需要
price * quantity,可以配合 脚本聚合 或在索引时预计算一个total_amount字段。
2.3 Avg(平均值)
json
GET /orders/_search
{
"size": 0,
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
返回结果:
json
{
"aggregations": {
"avg_price": {
"value": 1903.6
}
}
}
2.4 Max(最大值) & Min(最小值)
json
GET /orders/_search
{
"size": 0,
"aggs": {
"max_price": {
"max": { "field": "price" }
},
"min_price": {
"min": { "field": "price" }
}
}
}
返回结果:
json
{
"aggregations": {
"max_price": { "value": 7999.0 },
"min_price": { "value": 168.0 }
}
}
2.5 Cardinality(去重计数)
Cardinality 用于计算某个字段的不同值的数量,等价于 SQL 的 COUNT(DISTINCT field)。底层使用 HyperLogLog++ 算法,在精度和内存之间做了平衡。
json
GET /orders/_search
{
"size": 0,
"aggs": {
"unique_users": {
"cardinality": {
"field": "user_id"
}
}
}
}
返回结果:
json
{
"aggregations": {
"unique_users": {
"value": 5
}
}
}
精度控制 :Cardinality 默认精度阈值是 3000。对于大数据量,可以通过
precision_threshold参数调整精度:
json"cardinality": { "field": "user_id", "precision_threshold": 10000 }精度越高,内存消耗越大。通常设置为期望去重值的整数倍即可。
2.6 Stats(统计集合)
Stats 是一个复合指标聚合,一次性返回 count、min、max、avg、sum 五个统计值:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"price_stats": {
"stats": { "field": "price" }
}
}
}
返回结果:
json
{
"aggregations": {
"price_stats": {
"count": 10,
"min": 168.0,
"max": 7999.0,
"avg": 1903.6,
"sum": 19036.0
}
}
}
2.7 Extended Stats(扩展统计)
Extended Stats 在 Stats 的基础上增加了方差、标准差、平方和等高级统计指标:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"price_extended_stats": {
"extended_stats": { "field": "price" }
}
}
}
返回结果包含:count、min、max、avg、sum、sum_of_squares、variance、variance_population、variance_sampling、std_deviation、std_deviation_population、std_deviation_sampling。
应用场景:当需要分析数据的离散程度时,标准差和方差是非常有用的指标。比如判断价格分布是否异常集中或分散。
三、常用桶聚合:Terms、Range、Date Range、Histogram
桶聚合负责将文档分到不同的"桶"中,是最灵活的聚合类型。
3.1 Terms 聚合------按词条分桶
Terms 聚合根据某个字段的值进行分桶,类似于 SQL 的 GROUP BY。它是使用频率最高的桶聚合。
基本用法------统计各品类的订单数量:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": {
"field": "category",
"size": 10
}
}
}
}
返回结果:
json
{
"aggregations": {
"by_category": {
"buckets": [
{ "key": "数码", "doc_count": 4 },
{ "key": "服饰", "doc_count": 2 },
{ "key": "食品", "doc_count": 2 },
{ "key": "家居", "doc_count": 2 }
]
}
}
}
核心参数详解:
| 参数 | 说明 | 默认值 |
|---|---|---|
size |
返回的桶数量 | 10 |
order |
桶的排序方式 | _count 降序 |
min_doc_count |
最小文档数阈值 | 1 |
shard_size |
每个分片返回的桶数量 | size |
show_term_doc_count_error |
是否显示近似误差 | false |
进阶配置:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": {
"field": "category",
"size": 10,
"order": {
"_count": "desc"
},
"min_doc_count": 1,
"shard_size": 50
}
}
}
}
重要概念------Terms 聚合的近似性 :Terms 聚合是分布式的,协调节点向每个分片请求 top N 的结果,然后合并。如果某个词条均匀分布在所有分片上,它的全局计数可能被低估。增大
shard_size可以提高准确性,但会增加内存消耗。
3.2 Range 聚合------按数值范围分桶
Range 聚合根据数值范围将文档分到不同的桶中。每个桶由 from(包含)和 to(不包含)定义。
统计商品价格区间分布:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "key": "低价区", "from": 0, "to": 500 },
{ "key": "中价区", "from": 500, "to": 2000 },
{ "key": "高价区", "from": 2000, "to": 5000 },
{ "key": "奢侈品区", "from": 5000 }
]
}
}
}
}
返回结果:
json
{
"aggregations": {
"price_ranges": {
"buckets": [
{ "key": "低价区", "from": 0.0, "to": 500.0, "doc_count": 3 },
{ "key": "中价区", "from": 500.0, "to": 2000.0, "doc_count": 4 },
{ "key": "高价区", "from": 2000.0, "to": 5000.0, "doc_count": 2 },
{ "key": "奢侈品区", "from": 5000.0, "doc_count": 1 }
]
}
}
}
注意 :
from是包含的(≥),to是不包含的(<)。如果只指定from不指定to,则表示无上限;反之同理。
3.3 Date Range 聚合------按日期范围分桶
Date Range 是 Range 聚合的日期版本,专门处理日期字段。日期格式支持数学表达式,如 now-7d/d。
按时间维度统计订单分布:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"order_time_ranges": {
"date_range": {
"field": "order_date",
"format": "yyyy-MM-dd",
"ranges": [
{ "key": "本周", "from": "now-7d/d", "to": "now/d" },
{ "key": "上周", "from": "now-14d/d", "to": "now-7d/d" },
{ "key": "更早", "to": "now-14d/d" }
]
}
}
}
}
日期表达式速查:
| 表达式 | 含义 |
|---|---|
now |
当前时间 |
now-1d |
1天前 |
now-7d/d |
7天前(向下取整到天) |
now/M |
当前月的开始 |
now-1M/M |
上个月的开始 |
now+1h/h |
下一小时的开始 |
实战建议 :日期表达式中
/d、/M等后缀表示"取整到该精度",这对于时间范围聚合非常重要,能避免边界数据遗漏。
3.4 Histogram 聚合------等间距直方图分桶
Histogram 聚合按固定间隔将数值字段分成若干桶。每个桶的中心值、左右边界都是自动计算的。
以 1000 为间隔统计价格分布:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"price_histogram": {
"histogram": {
"field": "price",
"interval": 1000,
"min_doc_count": 0,
"extended_bounds": {
"min": 0,
"max": 8000
}
}
}
}
}
返回结果:
json
{
"aggregations": {
"price_histogram": {
"buckets": [
{ "key": 0.0, "doc_count": 3 },
{ "key": 1000.0, "doc_count": 4 },
{ "key": 2000.0, "doc_count": 2 },
{ "key": 3000.0, "doc_count": 0 },
{ "key": 4000.0, "doc_count": 0 },
{ "key": 5000.0, "doc_count": 0 },
{ "key": 6000.0, "doc_count": 0 },
{ "key": 7000.0, "doc_count": 1 },
{ "key": 8000.0, "doc_count": 0 }
]
}
}
}
核心参数说明:
| 参数 | 说明 |
|---|---|
interval |
桶的间隔大小 |
min_doc_count |
最小文档数,设为 0 可显示空桶 |
extended_bounds |
强制扩展显示范围 |
hard_bounds |
限制桶的上下界 |
missing |
缺失值的处理方式 |
3.5 Date Histogram 聚合------时间序列分析利器
Date Histogram 是 Histogram 的时间版本,按固定时间间隔分桶,是时序分析最常用的聚合。
json
GET /orders/_search
{
"size": 0,
"aggs": {
"orders_over_time": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day",
"format": "yyyy-MM-dd",
"min_doc_count": 0,
"extended_bounds": {
"min": "2024-03-01",
"max": "2024-03-10"
}
}
}
}
}
时间间隔选项:
| 间隔类型 | 可选值 |
|---|---|
calendar_interval |
minute、hour、day、week、month、quarter、year |
fixed_interval |
1ms、1s、1m、1h、1d(支持倍数如 30s、2h) |
选择建议 :
calendar_interval适合自然时间(如"每月"会自动处理不同月份的天数差异),fixed_interval适合固定间隔(如"每30天"严格按30天计算)。
四、多级聚合、嵌套聚合实战
真正的业务分析往往需要将多个聚合组合使用。嵌套聚合是 ElasticSearch 聚合能力的精髓所在。
4.1 桶内嵌套指标聚合
最简单的嵌套形式:在桶聚合内部添加指标聚合。
需求:统计各品类的总销售额和平均客单价:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"total_sales": {
"sum": { "field": "price" }
},
"avg_sales": {
"avg": { "field": "price" }
},
"order_count": {
"value_count": { "field": "order_id" }
}
}
}
}
}
返回结果:
json
{
"aggregations": {
"by_category": {
"buckets": [
{
"key": "数码",
"doc_count": 4,
"total_sales": { "value": 15396.0 },
"avg_sales": { "value": 3849.0 },
"order_count": { "value": 4 }
},
{
"key": "服饰",
"doc_count": 2,
"total_sales": { "value": 998.0 },
"avg_sales": { "value": 499.0 },
"order_count": { "value": 2 }
}
// ... 其他品类
]
}
}
}
4.2 桶内嵌套桶聚合(多级分桶)
桶聚合可以嵌套另一个桶聚合,实现多维度下钻分析。
需求:先按品类分组,再按价格区间分组:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"by_price_range": {
"range": {
"field": "price",
"ranges": [
{ "key": "500以下", "to": 500 },
{ "key": "500-2000", "from": 500, "to": 2000 },
{ "key": "2000以上", "from": 2000 }
]
}
}
}
}
}
}
返回结果结构:
by_category
├── 数码 (4)
│ ├── 500以下: 0
│ ├── 500-2000: 2
│ └── 2000以上: 2
├── 服饰 (2)
│ ├── 500以下: 1
│ ├── 500-2000: 1
│ └── 2000以上: 0
└── ...
4.3 三级嵌套:品类 → 时间 → 指标
需求:统计每个品类每天的销售总额和订单数:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"by_day": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day",
"format": "yyyy-MM-dd"
},
"aggs": {
"daily_revenue": {
"sum": { "field": "price" }
},
"daily_orders": {
"value_count": { "field": "order_id" }
}
}
}
}
}
}
}
架构师视角:这种三级嵌套(品类 → 日期 → 指标)是数据看板最常用的聚合模式。前端可以据此渲染出品类选择器 + 时间折线图 + 指标卡片的完整交互。
4.4 实战:电商销售分析仪表盘
将所学知识综合运用,构建一个完整的销售分析聚合查询:
json
GET /orders/_search
{
"size": 0,
"query": {
"bool": {
"filter": [
{ "term": { "status": "已完成" } },
{ "range": { "order_date": { "gte": "2024-03-01", "lte": "2024-03-31" } } }
]
}
},
"aggs": {
"总销售额": {
"sum": { "field": "price" }
},
"平均客单价": {
"avg": { "field": "price" }
},
"独立用户数": {
"cardinality": { "field": "user_id" }
},
"各品类销售统计": {
"terms": { "field": "category", "size": 10, "order": { "品类销售额": "desc" } },
"aggs": {
"品类销售额": {
"sum": { "field": "price" }
},
"品类订单数": {
"value_count": { "field": "order_id" }
},
"品类均价": {
"avg": { "field": "price" }
},
"每日趋势": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day",
"format": "yyyy-MM-dd",
"min_doc_count": 0,
"extended_bounds": {
"min": "2024-03-01",
"max": "2024-03-31"
}
},
"aggs": {
"日销售额": {
"sum": { "field": "price" }
}
}
}
}
},
"价格分布": {
"histogram": {
"field": "price",
"interval": 1000,
"min_doc_count": 0,
"extended_bounds": { "min": 0, "max": 8000 }
}
}
}
}
这段聚合实现了:
- 全局维度:总销售额、平均客单价、独立用户数
- 品类维度:每个品类的销售额、订单数、均价
- 时间维度:每个品类每天的销售额趋势
- 价格维度:商品价格的整体分布
注意 :聚合查询可以与
query条件组合使用。上面的查询先通过bool filter筛选出"已完成"且在3月份内的订单,再对筛选后的数据做聚合。这相当于 SQL 中的WHERE+GROUP BY。
五、聚合排序、聚合结果过滤、聚合性能优化
掌握了基本用法之后,如何让聚合结果更精确、查询更高效?这是从"会用"到"精通"的关键一步。
5.1 聚合排序
按桶的文档数排序
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": {
"field": "category",
"size": 10,
"order": { "_count": "asc" }
}
}
}
}
按桶的 Key 排序(字母序)
json
"order": { "_key": "asc" }
按子聚合的指标值排序
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": {
"field": "category",
"size": 10,
"order": { "total_sales": "desc" }
},
"aggs": {
"total_sales": {
"sum": { "field": "price" }
}
}
}
}
}
实战场景:运营想要看"哪个品类销售额最高",就用子聚合指标排序。这在构建排行榜类功能时非常实用。
5.2 聚合结果过滤
include/exclude------过滤 Terms 聚合的词条
json
GET /orders/_search
{
"size": 0,
"aggs": {
"selected_categories": {
"terms": {
"field": "category",
"include": ["数码", "家居"]
}
}
}
}
支持正则表达式过滤:
json
"include": "数.*"
桶选择器(Bucket Selector)------按指标值过滤桶
桶选择器是一种管道聚合,根据父聚合的指标值来决定保留哪些桶。
需求:只保留销售额超过 500 的品类:
json
GET /orders/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"total_sales": {
"sum": { "field": "price" }
},
"sales_filter": {
"bucket_selector": {
"buckets_path": {
"totalSales": "total_sales"
},
"script": "params.totalSales > 500"
}
}
}
}
}
}
参数说明:
buckets_path:指定引用哪个子聚合的结果script:过滤条件脚本,返回 true 的桶被保留
5.3 聚合作用域
global 聚合------突破 query 限制
默认情况下,聚合只在 query 匹配的文档范围内执行。如果需要在全量数据上做聚合(同时保留 query 的筛选),可以使用 global 聚合:
json
GET /orders/_search
{
"size": 0,
"query": {
"term": { "status": "已完成" }
},
"aggs": {
"completed_stats": {
"sum": { "field": "price" }
},
"all_orders_stats": {
"global": {},
"aggs": {
"total": {
"sum": { "field": "price" }
}
}
}
}
}
应用场景:数据看板上需要同时展示"已完成订单总额"和"全部订单总额"作为对比基准。
filter 聚合------为子聚合创建独立筛选
json
GET /orders/_search
{
"size": 0,
"aggs": {
"high_value_category": {
"filter": {
"range": { "price": { "gte": 1000 } }
},
"aggs": {
"by_category": {
"terms": { "field": "category" }
}
}
}
}
}
5.4 聚合性能优化
优化一:使用 doc_values 替 fielddata
这是最重要的聚合性能优化原则。
doc_values:基于磁盘的列式存储,用于 keyword、数值、日期、布尔、IP、地理坐标类型,默认开启。内存友好,但查询时需要从磁盘读取。fielddata:基于内存的数据结构,用于 text 字段。会占用大量 JVM 堆内存,可能导致 OOM。
黄金法则 :永远不要在 text 字段上做聚合! 应该使用 keyword 子字段:
json
PUT /orders
{
"mappings": {
"properties": {
"product_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
聚合时使用 product_name.keyword 而非 product_name。
优化二:设置 size: 0
json
GET /orders/_search
{
"size": 0,
"aggs": { ... }
}
当只需要聚合结果时,设置 size: 0 跳过文档的获取和排序,大幅减少内存和 CPU 消耗。
优化三:控制 Terms 聚合的 shard_size
json
"terms": {
"field": "category",
"size": 10,
"shard_size": 20
}
shard_size 决定每个分片返回的候选桶数量。默认等于 size,如果数据分布不均匀,可能导致结果不准确。建议设为 size 的 1.5~2 倍。
优化四:善用 filter 聚合减少计算量
如果只需要部分数据的聚合,先用 filter 聚合缩小范围:
json
"aggs": {
"active_users": {
"filter": { "term": { "status": "active" } },
"aggs": {
"by_region": {
"terms": { "field": "region" }
}
}
}
}
优化五:避免深度嵌套
嵌套层级越深,内存消耗呈指数增长。一般建议嵌套不超过 3 层。如果需要更复杂的分析,考虑以下方案:
- 将中间结果写入临时索引,再做下一级聚合
- 使用 Transform 功能预聚合数据
- 在应用层分步聚合
优化六:合理使用 execution_hint
对于 Terms 聚合,可以提示执行策略:
json
"terms": {
"field": "category",
"execution_hint": "map"
}
| execution_hint | 说明 |
|---|---|
map(默认) |
使用 Map 结构,适合桶数量较少的场景 |
global_ordinals |
使用全局序号,适合桶数量多且重复值多的场景 |
map_count |
额外记录文档数,适合只需要排序的场景 |
架构师建议 :在实际生产中,如果 Terms 聚合的字段基数很大(如 user_id),
global_ordinals通常性能更好。如果基数较小(如 category),map就足够了。
总结
本章系统地讲解了 ElasticSearch 聚合查询的核心知识,从基础概念到高级优化:
| 知识点 | 核心要点 |
|---|---|
| 聚合类型 | 桶聚合(分桶)+ 指标聚合(计算)+ 管道聚合(二次加工) |
| 指标聚合 | sum、avg、max、min、cardinality、stats |
| 桶聚合 | terms、range、date_range、histogram、date_histogram |
| 嵌套聚合 | 桶内嵌指标、桶内嵌桶、多级嵌套 |
| 结果控制 | 排序、过滤(include/exclude)、桶选择器 |
| 作用域 | global、filter |
| 性能优化 | doc_values 优先、size:0、控制 shard_size、避免深度嵌套 |
下一章预告 :第8章将深入 ElasticSearch 的集群架构,从节点角色到分片分配策略,从数据备份到跨集群复制,帮助你理解 ElasticSearch 在生产环境中的高可用设计。
如果这篇文章对你有帮助,欢迎 点赞 + 在看 + 转发 三连支持!有任何问题,欢迎在评论区留言讨论。