👋 你好,数据分析新手!
你是否熟悉 Excel 的透视表?它能轻松地对数据进行分组、求和、求平均,让你从一堆乱麻中快速看出端倪。
今天,我要告诉你一个好消息:Elasticsearch (ES) 也有一个"超级透视表"功能,它叫做"聚合 (Aggregation)"。
如果说查询 (query) 是从 ES 的"图书馆"里找书,那么聚合 (aggregation) 就是对这些书进行统计分析,比如"哪个作者的书最多?"、"平均每本书有多少页?"。
这篇文章将带你用最直观的方式,入门 ES 的聚合功能。
🛠️ 聚合的"菜谱":基本结构
和查询类似,聚合请求也有一个标准的 JSON 结构。我们同样通过 _search 端点发送,但这次我们把聚合指令放在 aggs (aggregations 的缩写) 字段里。
bash
# 基本结构
GET /你的索引名称/_search
{
"size": 0, // 设置为0,表示不返回具体文档,只返回聚合结果,更高效
"aggs": { // "aggs" 是 "aggregations" 的缩写
"你给结果起的名字": { // 比如 "avg_price"
"聚合类型": { // 比如 "avg"
"字段": "字段名" // 比如 "price"
}
}
}
}
别担心,下面的例子会让这个"菜谱"变得生动起来。
🧩 核心聚合类型:你的"数据积木"
聚合主要分为两大类,理解了它们,你就理解了聚合的精髓。
1. 桶聚合 (Bucket Aggregation) - "分组"
这是什么?
桶聚合就像 Excel 透视表里的"行"或"列",它负责将数据分门别类地放进不同的"桶"里。例如,按"商品类别"分组,每个类别就是一个"桶"。
最常用的桶聚合:terms
terms 聚合会为你统计每个"桶"里有多少文档。
场景: 统计一个"商品"索引中,每个**类别(category)**下有多少商品。
json
GET /products/_search
{
"size": 0,
"aggs": {
"products_by_category": { // 我们给这个聚合结果起个名字
"terms": {
"field": "category.keyword" // 按 category 字段分组
}
}
}
}
category.keyword: 通常对文本字段进行分组时,我们使用.keyword后缀,以确保 ES 对整个词进行精确分组,而不是分词。
返回结果可能像这样:
json
{
...
"aggregations": {
"products_by_category": {
"buckets": [
{ "key": "电子产品", "doc_count": 150 },
{ "key": "家居用品", "doc_count": 80 },
{ "key": "图书", "doc_count": 200 }
]
}
}
}
看,是不是很清晰?ES 告诉你,"电子产品"这个桶里有150个商品,"家居用品"有80个。这就像透视表的行标签和计数!
2. 指标聚合 (Metrics Aggregation) - "计算"
这是什么?
指标聚合就像 Excel 透视表里的"值"区域,它负责对放进"桶"里的数据进行数学计算。例如,求平均值、总和、最大值、最小值等。
常用的指标聚合:
avg:计算平均值sum:计算总和max/min:计算最大/最小值cardinality:计算不重复值的数量(类似COUNT(DISTINCT column))
场景 : 计算所有商品的平均价格(price)。
json
GET /products/_search
{
"size": 0,
"aggs": {
"average_price": { // 结果名
"avg": { // 聚合类型:平均值
"field": "price" // 要计算的字段
}
}
}
}
返回结果可能像这样:
json
{
...
"aggregations": {
"average_price": {
"value": 256.8 // 直接返回计算出的值
}
}
}
🚀 组合起来!像透视表一样工作
现在,让我们把"桶"和"指标"组合起来,完成一个真正的"透视表"操作。
终极场景 : 统计每个商品类别下的平均价格是多少?
这就像在 Excel 透视表里:
- 行 :商品类别 (Category) ->
terms桶聚合 - 值 :价格的平均值 (Average of Price) ->
avg指标聚合
ES 查询语句:
json
GET /products/_search
{
"size": 0,
"aggs": {
"avg_price_by_category": { // 第一层聚合:按类别分组(桶)
"terms": {
"field": "category.keyword"
},
"aggs": { // 在每个类别的"桶"内部,再进行子聚合
"avg_price": { // 给子聚合起个名字
"avg": { // 子聚合类型:计算平均值
"field": "price"
}
}
}
}
}
}
返回结果可能像这样:
json
{
...
"aggregations": {
"avg_price_by_category": {
"buckets": [
{
"key": "电子产品", // 桶1:电子产品
"doc_count": 150,
"avg_price": { "value": 1200.50 } // 桶1的平均值
},
{
"key": "家居用品", // 桶2:家居用品
"doc_count": 80,
"avg_price": { "value": 150.00 } // 桶2的平均值
},
{
"key": "图书", // 桶3:图书
"doc_count": 200,
"avg_price": { "value": 45.80 } // 桶3的平均值
}
]
}
}
}
这不就是你想要的透视表结果吗?!清晰、直观,一目了然。
💡 总结与下一步
恭喜你!你已经掌握了 ES 聚合的核心思想:
- 桶聚合 (
terms) :像透视表的行/列 ,用来分组。 - 指标聚合 (
avg,sum等) :像透视表的值 ,用来计算。 - 组合使用:在桶聚合内部嵌套指标聚合,实现强大的分层分析。
你的入门实践路径:
- 打开 Kibana 的 Dev Tools。
- 找一个你熟悉的索引(比如网站日志、商品数据等)。
- 尝试用
terms聚合对某个字段(如国家、城市、分类)进行分组。 - 再尝试在分组的基础上,计算某个数值字段(如价格、访问量)的平均值或总和。
ES 的聚合功能远不止于此,还有日期直方图 (date_histogram)、过滤 (filter)、嵌套聚合等更高级的玩法。但掌握了今天的"桶+指标"组合,你已经能解决 80% 的数据分析需求了!