[ELK实战] Elasticsearch 聚合查询二: Bucketing/桶聚合

简介: 目前在[官方文档]有4种聚合(Aggregations )方式分别是: 1. Metric (指标聚合): 最常用的聚合方式例如 平均值,求和等等 3. Bucketing (桶聚合): 就是常说的分组聚合 5. Matrix (矩阵聚合) :在多个字段上操作并根据从请求的文档字段提取的值生成矩阵结果的聚合族。与度量聚合和桶聚合不同,此聚合族尚不支持脚本。 7. Pipeline (管道聚合

简介

目前在官方文档有4种聚合(Aggregations )方式分别是:

  1. Metric (指标聚合):

    最常用的聚合方式例如 平均值,求和等等
  2. Bucketing (桶聚合):

    就是常说的分组聚合
  3. Matrix (矩阵聚合) :

在多个字段上操作并根据从请求的文档字段提取的值生成矩阵结果的聚合族。与度量聚合和桶聚合不同,此聚合族尚不支持脚本。

  1. Pipeline (管道聚合):

由于每个 bucket 有效地定义了一个文档集(属于 bucket 的所有文档) ,因此可以潜在地在 bucket 级别上关联聚合,并且这些聚合将在 bucket 的上下文中执行。这就是聚合的真正威力所在: 聚合可以被嵌套!

方法 / 步骤

一: 简介并加入测试数据

1.1 聚合相关参数

指标聚合有参数有:range / date_range / terms / histogram / date_histogram / ...

聚合类型 聚合参数 简介
Bucketing Range Aggregation - 范围聚合查询
Bucketing Date Range Aggregation - 时间范围聚合查询
Bucketing Terms Aggregation - 分组统计
Bucketing Histogram Aggregation - 直方图统计
Bucketing Date histogram aggregation - 时间直方图统计

1.2 DSL 查询格式

"aggregations" : {
    "<aggregation_name>" : {
        "<aggregation_type>" : {
            <aggregation_body>
        }
        [,"meta" : {  [<meta_data_body>] } ]?
        [,"aggregations" : { [<sub_aggregation>]+ } ]?
    }
    [,"<aggregation_name_2>" : { ... } ]*
}

1.3 插入批量测试数据

POST /staff/_bulk
{"index":{"_id":1}}
{"name":"zs","realname":"张三","age":10,"birthday":"2018-12-27","salary":1000.0,"address":"北京市北海公园"}
{"index":{"_id":2}}
{"name":"ls","realname":"李四","age":20,"birthday":"2017-10-20","salary":2000.0,"address":"北京市京东大峡谷"}
{"index":{"_id":3}}
{"name":"ww","realname":"王五","age":30,"birthday":"2016-03-15","salary":3000.0,"address":"北京市陶然亭"}
{"index":{"_id":4}}
{"name":"zl","realname":"赵六","age":40,"birthday":"2003-04-19","salary":4000.0,"address":"北京市玉渊潭"}
{"index":{"_id":5}}
{"name":"tq","realname":"田七","age":50,"birthday":"2001-08-11","salary":5000.0,"address":"北京市圆明园"}

插入完成后,查看索引数据:

GET /staff/_search

在这里插入图片描述

二: 常规查询

2.1 Range Aggregation / 返回聚合

每个范围表示一个桶。在聚合过程中,将根据每个bucket范围和相关/匹配文档的“bucket”检查从每个文档提取的值。

如: 统计0-20岁,20-40岁,40~60岁各个区间段的用户人数

POST /staff/_search
{
  "aggs": {
    "age_ranges_count": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 0,
            "to": 20
          },
          {
            "from": 20,
            "to": 40
          },
          {
            "from": 40,
            "to": 60
          }
        ]
      }
    }
  }
}
  • 返回内容
    .....
  "aggregations" : {
    "age_ranges_count" : {
      "buckets" : [
        {
          "key" : "0.0-20.0",
          "from" : 0.0,
          "to" : 20.0,
          "doc_count" : 1
        },
        {
          "key" : "20.0-40.0",
          "from" : 20.0,
          "to" : 40.0,
          "doc_count" : 2
        },
        {
          "key" : "40.0-60.0",
          "from" : 40.0,
          "to" : 60.0,
          "doc_count" : 2
        }
      ]
    }
  }
      .....
  • 如果第一个区间开始值和最后一个区间结束值不想指定的话,可以不用写from和to,如下:
POST /staff/_search
{
  "aggs": {
    "age_ranges_count": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "to": 20
          },
          {
            "from": 20,
            "to": 40
          },
          {
            "from": 40,
            "to": 60
          }
        ]
      }
    }
  }
}
  • 返回内容
....
  "aggregations" : {
    "age_ranges_count" : {
      "buckets" : [
        {
          "key" : "*-20.0",
          "to" : 20.0,
          "doc_count" : 1
        },
        {
          "key" : "20.0-40.0",
          "from" : 20.0,
          "to" : 40.0,
          "doc_count" : 2
        },
        {
          "key" : "40.0-60.0",
          "from" : 40.0,
          "to" : 60.0,
          "doc_count" : 2
        }
      ]
    }
  }
  ....

2.2 Date Range Aggregation / 时间范围聚合

此聚合与Range Aggregation常规范围聚合的主要区别在于,可以用日期数学表达式表示from和to值,而且还可以指定返回from和to响应字段的日期格式。注意,此聚合包含每个范围的from值并排除to值。

  • now+10y:表示从现在开始的第10年。
  • now+10M:表示从现在开始的第10个月。
  • 1990-01-10||+20y:表示从1990-01-01开始后的第20年,即2010-01-01。
  • now/y:表示在年位上做舍入运算。

如: 统计生日在2017年、2018年、2019年的用户

now/y:当前年的1月1日
now:当前时间
now/y-1y:当前年上一年的1月1日
POST /staff/_search
{
  "aggs": {
    "birthday_count": {
      "date_range": {
        "field": "birthday",
        "format": "yyyy-MM-dd",
        "ranges": [
          {
            "from": "now/y-1y",
            "to": "now/y"
          },
          {
            "from": "now/y-2y",
            "to": "now/y-1y"
          },
          {
            "from": "now/y-3y",
            "to": "now/y-2y"
          }
        ]
      }
    }
  }
}
  • 返回数据
  "aggregations" : {
    "birthday_count" : {
      "buckets" : [
        {
          "key" : "2019-01-01-2020-01-01",
          "from" : 1.5463008E12,
          "from_as_string" : "2019-01-01",
          "to" : 1.5778368E12,
          "to_as_string" : "2020-01-01",
          "doc_count" : 0
        },
        {
          "key" : "2020-01-01-2021-01-01",
          "from" : 1.5778368E12,
          "from_as_string" : "2020-01-01",
          "to" : 1.6094592E12,
          "to_as_string" : "2021-01-01",
          "doc_count" : 0
        },
        {
          "key" : "2021-01-01-2022-01-01",
          "from" : 1.6094592E12,
          "from_as_string" : "2021-01-01",
          "to" : 1.6409952E12,
          "to_as_string" : "2022-01-01",
          "doc_count" : 0
        }
      ]
    }
  }

2.3 Terms Aggregation / 分组聚合

  • 对年龄进行聚合,显示3条数据

POST /staff/_search
{
  "aggs": {
    "age_count": {
      "terms": {
        "field": "age",
        "size": 3
      }
    }
  }
}
  • 聚合结果

key年龄 为10,20 ,30各为一条

    ......
  "aggregations" : {
    "age_count" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 2,
      "buckets" : [
        {
          "key" : 10,
          "doc_count" : 1
        },
        {
          "key" : 20,
          "doc_count" : 1
        },
        {
          "key" : 30,
          "doc_count" : 1
        }
      ]
    }
  }
      ......

2.4 Histogram Aggregation / 直方图聚合

它与前面介绍的Range聚合非常像,只不过Range可以任意划分区间,而Histogram做等间距划分。既然是等间距划分,那么参数里面必然有距离参数,就是interval参数。
如:根据年龄间隔(20岁)统计各个年龄段的员工总人数

POST /staff/_search?size=0
{
  "aggs": {
    "salary_value_count": {
      "value_count": {
        "field": "salary"
      }
    }
  }
}
  • 返回结果
    .....
  "aggregations" : {
    "age_histogram_count" : {
      "buckets" : [
        {
          "key" : 0.0,
          "doc_count" : 1
        },
        {
          "key" : 20.0,
          "doc_count" : 2
        },
        {
          "key" : 40.0,
          "doc_count" : 2
        }
      ]
    }
  }
      .....

2.5 Date histogram aggregation / 时间直方图聚合

日期直方图聚合,专门对时间类型的字段做直方图聚合。这种需求是比较常用见得的,我们在统计时,通常就会按照固定的时间断(1个月或1年等)来做统计

如:按年统计用户生日的总人数

POST /staff/_search
{
  "aggs": {
    "birthday_data_histogram_count": {
      "date_histogram": {
        "field": "birthday",
        "interval": "year",
        "format": "yyyy-MM-dd"
      }
    }
  }
}
  • 返回结果
    .....
  "aggregations" : {
    "birthday_data_histogram_count" : {
      "buckets" : [
        {
          "key_as_string" : "2001-01-01",
          "key" : 978307200000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2002-01-01",
          "key" : 1009843200000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2003-01-01",
          "key" : 1041379200000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2004-01-01",
          "key" : 1072915200000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2005-01-01",
          "key" : 1104537600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2006-01-01",
          "key" : 1136073600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2007-01-01",
          "key" : 1167609600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2008-01-01",
          "key" : 1199145600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2009-01-01",
          "key" : 1230768000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2010-01-01",
          "key" : 1262304000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2011-01-01",
          "key" : 1293840000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2012-01-01",
          "key" : 1325376000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2013-01-01",
          "key" : 1356998400000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2014-01-01",
          "key" : 1388534400000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2015-01-01",
          "key" : 1420070400000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2016-01-01",
          "key" : 1451606400000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2017-01-01",
          "key" : 1483228800000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2018-01-01",
          "key" : 1514764800000,
          "doc_count" : 1
        }
      ]
    }
  }
      .....

三: 聚合查询嵌套使用

通过嵌套,可以使得metric类型的聚合操作作用在每一bucket上。我们可以使用ES的嵌套聚合操作来完成稍微复杂一点的统计功能。

3.1 统计每年中用户的最高工资

POST /staff/_search
{
  "aggs": {
    "birthday_data_histogram_count": {
      "date_histogram": {
        "field": "birthday",
        "interval": "year",
        "format": "yyyy-MM-dd"
      },
      "aggs": {
        "max_salary": {
          "max": {
            "field": "salary"
          }
        }
      }
    }
  }
}
  • 返回结果
    .....
  "aggregations" : {
    "birthday_data_histogram_count" : {
      "buckets" : [
        {
          "key_as_string" : "2001-01-01",
          "key" : 978307200000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 5000.0
          }
        },
        {
          "key_as_string" : "2002-01-01",
          "key" : 1009843200000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2003-01-01",
          "key" : 1041379200000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 4000.0
          }
        },
        {
          "key_as_string" : "2004-01-01",
          "key" : 1072915200000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2005-01-01",
          "key" : 1104537600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2006-01-01",
          "key" : 1136073600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2007-01-01",
          "key" : 1167609600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2008-01-01",
          "key" : 1199145600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2009-01-01",
          "key" : 1230768000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2010-01-01",
          "key" : 1262304000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2011-01-01",
          "key" : 1293840000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2012-01-01",
          "key" : 1325376000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2013-01-01",
          "key" : 1356998400000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2014-01-01",
          "key" : 1388534400000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2015-01-01",
          "key" : 1420070400000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2016-01-01",
          "key" : 1451606400000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 3000.0
          }
        },
        {
          "key_as_string" : "2017-01-01",
          "key" : 1483228800000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 2000.0
          }
        },
        {
          "key_as_string" : "2018-01-01",
          "key" : 1514764800000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 1000.0
          }
        }
      ]
    }
  }
      .....

先通过date_histogram按照年分组,然后再通过嵌套max聚合查询统计出每年最高工资是多少。

3.2 求每个年龄区间段的工资总和

....
  "aggregations" : {
    "age_ranges_count" : {
      "buckets" : [
        {
          "key" : "0.0-20.0",
          "from" : 0.0,
          "to" : 20.0,
          "doc_count" : 1,
          "sum_salary" : {
            "value" : 1000.0
          }
        },
        {
          "key" : "20.0-40.0",
          "from" : 20.0,
          "to" : 40.0,
          "doc_count" : 2,
          "sum_salary" : {
            "value" : 5000.0
          }
        },
        {
          "key" : "40.0-60.0",
          "from" : 40.0,
          "to" : 60.0,
          "doc_count" : 2,
          "sum_salary" : {
            "value" : 9000.0
          }
        }
      ]
    }
  }
  ....

参考资料 & 致谢

[1]官方文档
[2] ElasticSearch全文搜索引擎之Aggregation聚合查询(结合Kibana)

相关实践学习
以电商场景为例搭建AI语义搜索应用
本实验旨在通过阿里云Elasticsearch结合阿里云搜索开发工作台AI模型服务,构建一个高效、精准的语义搜索系统,模拟电商场景,深入理解AI搜索技术原理并掌握其实现过程。
ElasticSearch 最新快速入门教程
本课程由千锋教育提供。全文搜索的需求非常大。而开源的解决办法Elasricsearch(Elastic)就是一个非常好的工具。目前是全文搜索引擎的首选。本系列教程由浅入深讲解了在CentOS7系统下如何搭建ElasticSearch,如何使用Kibana实现各种方式的搜索并详细分析了搜索的原理,最后讲解了在Java应用中如何集成ElasticSearch并实现搜索。 &nbsp;
目录
相关文章
|
5月前
|
缓存 监控 前端开发
顺企网 API 开发实战:搜索 / 详情接口从 0 到 1 落地(附 Elasticsearch 优化 + 错误速查)
企业API开发常陷参数、缓存、错误处理三大坑?本指南拆解顺企网双接口全流程,涵盖搜索优化、签名验证、限流应对,附可复用代码与错误速查表,助你2小时高效搞定开发,提升响应速度与稳定性。
|
5月前
|
JSON Java API
(ELK)ElasticSearch8.7 搭配 SpringDataElasticSearch5.1 的使用
截至2023/7/11日,全网最全最直白的SpringDataElasticSearch5.1
352 3
|
存储 运维 监控
超越传统模型:从零开始构建高效的日志分析平台——基于Elasticsearch的实战指南
【10月更文挑战第8天】随着互联网应用和微服务架构的普及,系统产生的日志数据量日益增长。有效地收集、存储、检索和分析这些日志对于监控系统健康状态、快速定位问题以及优化性能至关重要。Elasticsearch 作为一种分布式的搜索和分析引擎,以其强大的全文检索能力和实时数据分析能力成为日志处理的理想选择。
1011 6
|
12月前
|
数据采集 JSON 数据挖掘
Elasticsearch 的DSL查询,聚合查询与多维度数据统计
Elasticsearch的DSL查询与聚合查询提供了强大的数据检索和统计分析能力。通过合理构建DSL查询,用户可以高效地搜索数据,并使用聚合查询对数据进行多维度统计分析。在实际应用中,灵活运用这些工具不仅能提高查询效率,还能为数据分析提供深入洞察。理解并掌握这些技术,将显著提升在大数据场景中的分析和处理能力。
624 20
|
11月前
|
人工智能 自然语言处理 运维
让搜索引擎“更懂你”:AI × Elasticsearch MCP Server 开源实战
本文介绍基于Model Context Protocol (MCP)标准的Elasticsearch MCP Server,它为AI助手(如Claude、Cursor等)提供与Elasticsearch数据源交互的能力。文章涵盖MCP概念、Elasticsearch MCP Server的功能特性及实际应用场景,例如数据探索、开发辅助。通过自然语言处理,用户无需掌握复杂查询语法即可操作Elasticsearch,显著降低使用门槛并提升效率。项目开源地址:&lt;https://github.com/awesimon/elasticsearch-mcp&gt;,欢迎体验与反馈。
2862 1
ELK 圣经:Elasticsearch、Logstash、Kibana 从入门到精通
ELK是一套强大的日志管理和分析工具,广泛应用于日志监控、故障排查、业务分析等场景。本文档将详细介绍ELK的各个组件及其配置方法,帮助读者从零开始掌握ELK的使用。
|
存储 监控 安全
|
存储 JSON 监控
大数据-167 ELK Elasticsearch 详细介绍 特点 分片 查询
大数据-167 ELK Elasticsearch 详细介绍 特点 分片 查询
939 4
|
11月前
|
安全 Java Linux
Linux安装Elasticsearch详细教程
Linux安装Elasticsearch详细教程
1950 64
|
10月前
|
JSON 安全 数据可视化
Elasticsearch(es)在Windows系统上的安装与部署(含Kibana)
Kibana 是 Elastic Stack(原 ELK Stack)中的核心数据可视化工具,主要与 Elasticsearch 配合使用,提供强大的数据探索、分析和展示功能。elasticsearch安装在windows上一般是zip文件,解压到对应目录。文件,elasticsearch8.x以上版本是自动开启安全认证的。kibana安装在windows上一般是zip文件,解压到对应目录。elasticsearch的默认端口是9200,访问。默认用户是elastic,密码需要重置。
5149 0