前一篇已经系统介绍过查询语法,详细可直接看上一篇文章(理解DSL语法(一)),本篇主要介绍DSL中的另一部分:聚合
理解Es中的聚合
虽然Elasticsearch 是一个基于 Lucene 的搜索引擎,但也提供了聚合(aggregations)的功能,允许用户对数据进行统计和分析。聚合可以按照不同的维度对数据进行分组和汇总,从而得到有意义的统计信息。这也是Es很多场景下被当作分析工具使用的原因。
聚合语法
使用上来讲,es的聚合就相当于SQL中的group by,在DSL中主要使用aggs关键字和size关键字来控制:
{
"size":0,
"aggs":{
"TestName":{ //自定义的聚合名称
"term":{ //聚合类型关键字,根据聚合类型来
"field":"title" //需要聚合的字段
}
}
}
}
这里着重说一下size关键字,如果单纯进行聚合,而不需要实际数据,最好这里size设置为0,设置size为0在进行聚合时,会默认触发Es的缓存机制,能够很有效的提升性能。
当然聚合也可以搭配查询query使用,即对查询的数据进行聚合,例如我们对最近一天的文章,聚合一下标题:
{
"query":{
"bool":{
"filter":[
{
"range":{
"create_time":{
"gte":"now - 1d",
"lte":"now"
}
}
}
]
}
}
"size":0,
"aggs":{
"TestName":{ //自定义的聚合名称
"term":{ //聚合类型关键字,根据聚合类型来
"field":"title" //需要聚合的字段
}
}
}
}
这里Es收到请求后,会先根据query中的条件去检索满足创建时间在近一天内的所有文档,然后对这些文档进行桶聚合,以title字段为桶,将title内容一致的文档放入桶内。
聚合的种类
总的来看,Es的聚合可以分为四类,即Bucketing Aggregations、Metric Aggregations、Matrix Aggregations、Pipeline Aggregations。
Bucketing Aggregations
将数据分桶,类似于 SQL 中的 GROUP BY
。例如,可以根据某个字段的不同值将数据分组,然后对每个分组进行统计,对于字段和内容都有一定的限制。
常用的聚合关键字有:
关键字 | 描述 | 适用字段类型 |
Terms | Terms 聚合根据指定字段的确切值将文档分组。它类似于 SQL 中的 GROUP BY 语句。 | keyword |
Histogram | 直方图聚合将数值字段划分为指定间隔的桶,并计算每个桶中的文档数量。 | 数值类型(
|
Date Histogram | 日期直方图聚合类似于直方图聚合,但它专门用于日期字段,允许你根据时间间隔(如天、周、月等)来分组数据 | date |
Range | 范围聚合允许你根据指定的范围将数据分组,每个范围定义了上界和下界。 | 数值类型 (
|
IP Range | IP 范围聚合允许你根据 IP 地址的范围将数据分组。 | ip |
Date Range | 日期范围聚合是范围聚合的日期版本,专门用于日期字段。 | date |
Filter/Filters | 过滤器聚合根据一个或多个过滤器条件将数据分组,每个过滤器条件定义了一个桶。 | 可以应用于任何类型的字段,但通常与布尔查询结合使用来定义过滤器条件。 |
Nested | 嵌套聚合应用于嵌套字段,它允许你根据嵌套对象中的字段值对嵌套文档进行分组。 | object或nested |
详细的可查阅ElasticSearch的官网,这里仅列出常用的,我们假设Es中存在以下一个数据集合:
[
{"name": "Book A", "category": "Fiction", "price": 9.99, "publish_date": "2020-01-01"},
{"name": "Book B", "category": "Science", "price": 15.00, "publish_date": "2021-06-15"},
{"name": "Book C", "category": "Fiction", "price": 12.50, "publish_date": "2022-03-10"},
{"name": "Book D", "category": "Education", "price": 8.50, "publish_date": "2019-09-20"},
{"name": "Book E", "category": "Science", "price": 20.00, "publish_date": "2023-01-05"}
]
并针对该数据集,进行相关的聚合样例:
Terms Aggregation聚合
查看有多少种category以及每种的文档数量。
示例:
{
"size":0,
"aggs": {
"genres": {
"terms": {
"field": "category" // genre必须为keyword类型
"size":3 //根据文档数量倒叙展示条数,默认不填写则仅展示10个
}
}
}
}
//输出:
{
"category": {
"buckets": [
{"key": "Fiction", "doc_count": 2},
{"key": "Science", "doc_count": 2},
{"key": "Education", "doc_count": 1}
]
}
}
Histogram Aggregation 聚合
按价格区间聚合书籍
{
"size":0,
"aggs": {
"price_distribution": {
"histogram": {
"field": "price",
"interval": 5 //以5元为一个段
}
}
}
}
//输出:
{
"aggregations": {
"price_distribution": {
"buckets": [
{ "key": 5, "doc_count": 1 },
{ "key": 10, "doc_count": 2 },
{ "key": 15, "doc_count": 2 }
]
}
}
}
Date Histogram Aggregation 聚合
按年份查看出版书籍的数量
{
"size":0,
"aggs": {
"books_over_time": {
"date_histogram": {
"field": "publish_date",
"calendar_interval": "year" //查询区间可以指定单位
}
}
}
}
//输出
{
"aggregations": {
"books_over_time": {
"buckets": [
{ "key_as_string": "2019", "doc_count": 1 },
{ "key_as_string": "2020", "doc_count": 1 },
{ "key_as_string": "2021", "doc_count": 1 },
{ "key_as_string": "2022", "doc_count": 1 },
{ "key_as_string": "2023", "doc_count": 1 }
]
}
}
}
其中对于date_histogram使用较多,这里单独列一下关于date_histogram的相关参数
-
calendar_interval:按照日历时间间隔(如年、季度、月、周、日等)来创建桶。
-
fixed_interval:按照固定时间间隔(如1小时、5分钟等)来创建桶,不考虑日历界限。
-
min_doc_count:设置为 0 或更大的值,以忽略那些文档计数小于该值的桶。
-
extended_bounds:允许聚合查询返回超出正常查询范围之外的桶,例如在直方图的开始或结束之前添加额外的桶。
-
order:指定桶的排序方式,可以是
asc
(升序)或desc
(降序)。 -
format:自定义日期格式,用于指定桶的 key 值的日期格式。
-
time_zone:指定时区来应用到聚合上,特别是对于固定间隔的聚合。
-
pre_zone 和 post_zone:与
extended_bounds
结合使用,指定额外桶的时区。
{
"size": 0,
"aggs": {
"publish_monthly": {
"date_histogram": {
"field": "publish_date",
"calendar_interval": "month", // 每月一个桶
"min_doc_count": 1, // 只包括至少有一个文档的桶
"extended_bounds": {
"min": "2019-01-01",
"max": "2023-12-31"
}, // 设置聚合的最小和最大界限
"order": "desc", // 桶按降序排序
"format": "yyyy-MM", // 桶 key 的格式
"time_zone": "Europe/Berlin" // 使用柏林时区
}
}
}
}
Range Aggregation聚合
查看价格区间内书籍的数量
{
"size":0,
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "from": 0, "to": 10 },
{ "from": 10, "to": 20 }
]
}
}
}
}
//输出
{
"aggregations": {
"price_ranges": {
"buckets": [
{ "from": 0, "to": 10, "doc_count": 2 },
{ "from": 10, "to": 20, "doc_count": 3 }
]
}
}
}
Filters Aggregation聚合
同时筛选 Fiction
和 Science
类别的书籍,并分别计算数量。
{
"size":0,
"aggs": {
"category_filters": {
"filters": {
"filters": {
"Fiction": {
"term": {
"category.keyword": "Fiction"
}
},
"Science": {
"term": {
"category.keyword": "Science"
}
}
}
}
}
}
}
//输出
{
"aggregations": {
"category_filters": {
"buckets": {
"Fiction": { "doc_count": 2 },
"Science": { "doc_count": 2 }
}
}
}
}
这里特殊说明一下,针对以上场景,也可以使用:
{
"query": {
"bool": {
"filter": [
{
"terms": {
"category": ["Fiction", "Science"]
}
}
]
}
},
"size": 0,
"aggs": {
"category": {
"terms": {
"field": "category"
}
}
}
}
不同的是,使用这种聚合,Es的需要进行两次操作,即:先根据query条件,进行数据查询,再对查询结果进行聚合,而Filters聚合则只有一次操作。在相同场景下,考虑性能的话,使用 filters
聚合可能在某些情况下更有效率,因为它可以利用 Elasticsearch 的缓存机制,特别是当这些特定的过滤条件经常被查询时。
Composite Aggregation聚合
按 category
和 publish_date
的每个月份组合聚合书籍。
{
"size": 0,
"aggs": {
"category_date_composite": {
"composite": {
"sources": [
{ "category": { "terms": { "field": "category.keyword" } } },
{ "date": { "date_histogram": { "field": "publish_date", "calendar_interval": "month" } } }
],
"size": 10
}
}
}
}
//输出
{
"composite_of_category_and_date": {
"buckets": [
{"key": {"category": "Fiction", "date": "2020-01"}, "doc_count": 1},
{"key": {"category": "Fiction", "date": "2022-03"}, "doc_count": 1},
{"key": {"category": "Science", "date": "2021-06"}, "doc_count": 1},
{"key": {"category": "Science", "date": "2023-01"}, "doc_count": 1}
]
}
}
Metric Aggregations
对数据进行数学运算,如计算平均值、总和、最小值、最大值等。此类大多对数字类型的字段进行聚合。
关键字 | 描述 |
Sum Aggregation | 计算数值字段的总和 |
Avg Aggregation | 计算数值字段的平均值 |
Min Aggregation | 找出数值字段中的最小值 |
Max Aggregation | 找出数值字段中的最大值 |
Stats Aggregation | 返回字段的多个统计度量,包括最小值、最大值、平均值和总和。 |
Cardinality Aggregation | 计算字段中唯一值的近似数量,对于大数据集非常有用,因为它比value_count更高效。 |
一般配合桶查询使用,对标的是SQL中的SUM、MAX等数学函数
Cardinality Aggregation
查看一共有多少文档:
{
"size":0,
"aggs": {
"countALl": {
"cardinality": {
"field": "_id"
}
}
}
}
//输出
{
"aggregations": {
"countALl": {
"value": 3
}
}
}
Min/Max Aggregation
//查看书籍最贵的价格
{
"size":0,
"aggs": {
"maximum_price": {
"max": {
"field": "price"
}
}
}
}
//输出:
{
"aggregations": {
"maximum_price": {
"value": 20.0
}
}
}
//查看书籍最便宜的价格
{
"size":0,
"aggs": {
"min_price": {
"min": {
"field": "price"
}
}
}
}
//输出
//输出:
{
"aggregations": {
"min_price": {
"value": 5.0
}
}
}
Sum/Avg Aggregation
//对库内书籍价格求和
{
"aggs": {
"all_price": {
"sum": {
"field": "price"
}
}
}
}
//输出:
{
"aggregations": {
"all_price": {
"value": 13.398
}
}
}
//对库内书籍价格求均值
{
"aggs": {
"average_price": {
"avg": {
"field": "price"
}
}
}
}
//输出
{
"aggregations": {
"average_price": {
"value": 13.398
}
}
}
Stats Aggregation
查看价格的综合统计
{
"size":0,
"aggs": {
"price_stats": {
"stats": {
"field": "price"
}
}
}
}
//输出:
{
"aggregations": {
"price_stats": {
"count": 5,
"min": 8.5,
"max": 20.0,
"avg": 13.398,
"sum": 66.99
}
}
}
聚合嵌套
语法格式为:
{
"size":0,
"aggs":{
"One":{ // 一层桶名称
"terms":{
"field":"fielda"
},
"aggs":{ //一层桶下二层聚合
}
}
}
}
以书籍书籍为例,查看每类书籍的平均价格,则可以先对书籍类型进行terms聚合,再在terms桶内,获取桶内书籍的平均价格:
//DSL
{
"size": 0,
"aggs": {
"categories": {
"terms": {
"field": "keyword"
},
"aggs": {
"average_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
//输出结果
{
"aggregations": {
"categories": {
"buckets": [
{
"key": "Fiction",
"doc_count": 2,
"average_price": {
"value": 11.245
}
},
{
"key": "Science",
"doc_count": 2,
"average_price": {
"value": 17.5
}
},
{
"key": "Education",
"doc_count": 1,
"average_price": {
"value": 8.5
}
}
]
}
}
}
也可以查看发布年限,每年里发布书籍的总价格:
{
"size": 0,
"aggs": {
"publish_years": {
"date_histogram": {
"field": "publish_date",
"calendar_interval": "year"
},
"aggs": {
"total_price": {
"sum": {
"field": "price"
}
}
}
}
}
}
//输出
{
"aggregations": {
"publish_years": {
"buckets": [
{
"key_as_string": "2019",
"key": 1577836800000,
"doc_count": 1,
"total_price": {
"value": 8.5
}
},
{
"key_as_string": "2020",
"key": 1609459200000,
"doc_count": 1,
"total_price": {
"value": 9.99
}
},
{
"key_as_string": "2021",
"key": 1609459200000,
"doc_count": 1,
"total_price": {
"value": 15.0
}
},
{
"key_as_string": "2022",
"key": 1640995200000,
"doc_count": 1,
"total_price": {
"value": 12.5
}
},
{
"key_as_string": "2023",
"key": 1672531200000,
"doc_count": 1,
"total_price": {
"value": 20.0
}
}
]
}
}
}
标签:count,category,聚合,doc,price,语法,DSL,key,Es
From: https://blog.csdn.net/qq_40690073/article/details/139519613