目录
概念:Bucket可以理解为一个桶,符合要求的放入一个桶中,相当于mysql中的groupBy
一,创建索引数据,参考Elasticsearch(三)--Metric(指标)
3.1过滤获取goodType为手机数码的桶,并求该桶平均值
3.2过滤获取goodType为手机数码或者goodName为男士外套的桶
4.1根据价格区间为10000分桶,同时如果桶中没有文档就不显示桶
Date Histogram Aggregation(日期聚合)
说明:该博客对应的Elasticsearch 的版本为7.8.0;测试工具为postman
概念:Bucket可以理解为一个桶,符合要求的放入一个桶中,相当于mysql中的groupBy
本篇博客主要针对于terms aggs, filter aggs,histogram aggs,range aggs,date aggs五个关键字展开.
一,创建索引数据,参考Elasticsearch(三)--Metric(指标)
Aggregation语法
- Aggregation是search的一部分,一般情况下,建议将其size设为0;
Terms Aggregation (术语聚合)
terms聚合应该是一个类型的字段keyword或适合桶聚合的任何其他数据类型。为了使用它,text需要启用 fielddata。
默认情况下,terms聚合将返回按 排序的前十个术语的桶doc_count。可以通过设置size参数来更改此默认行为。
{
"aggs":{
"term_goodType":{
"terms":{
"field":"goodType",
"size":3, //返回排序后的前三个桶(默认情况下,桶
//按doc_count降序排列)
"order":{
"_count":"asc" //按照每个桶内文档的个数进行升序排列
}
}
}
}
}
运行结果
注意:关于排序的介绍
1,内置排序
_count:按文档数排序
_key:按词项的字符串值的字母顺序排序
2,按单值指标子聚合(由聚合名称标识)对存储桶进行排序
3,按多值指标子聚合(由聚合名称标识)对存储桶进行排序
按单值指标子聚合(由聚合名称标识)对存储桶进行排序
{
"aggs":{
"term_goodType":{
"terms":{
"field":"goodType",
//"size":3,
"order":{
"in_bucket_max_goodPrice":"desc" //对该聚合名称进行降序排序
}
},
"aggs":{
"in_bucket_max_goodPrice":{ //聚合名称的具体实现
"max":{
"field":"goodPrice"
}
}
}
}
}
}
运行结果
按多值指标子聚合(由聚合名称标识)对存储桶进行排序
{
"aggs":{
"term_goodType":{
"terms":{
"field":"goodType",
//"size":3,
"order":{
"in_bucket_max_goodPrice":"desc", //先按照每个桶内该字段的最大值降序排列
"top_hit":"desc" //最大值相同的再按照相关度得分降序排列
}
},
"aggs":{
"in_bucket_max_goodPrice":{
"max":{
"field":"goodPrice"
}
},
"top_hit":{
"max": {
"script": {"source": "_score"}
}
}
}
}
}
}
运行结果
Bucket size & Top hits Demo
- 应用场景:当获取分桶后,桶内最匹配的顶部文档列表
- Size:按照年龄分桶,找出指定数据量的分桶信息
- Top Hits:查看各个工种中,年纪最大的3名员工
- 优化Terms Aggregation性能
- 聚合查询频繁且对性能要求高,索引不断有新的文档写入:将下面字段打开,一旦有新的文档写入,term Aggregation就会被提前计算好,当去做聚合分析的时候,速度会有很大的提升
Filter Aggregation(过滤聚合)
过滤器聚集通过定义一个或多个过滤器来区分桶,满足过速器条件的文档将落入这个过滤器形成的桶中。过滤器聚集分为单桶和多桶两种,对应的聚集类型自然就是filter和filters
Filter Aggregation 和 Filters Aggregation:多桶聚合,其中每个桶包含与查询匹配的文档
Filter Aggreagtion 只能指定一个过滤条件,响应也只是单个桶。如果想要只对多个特定值进行聚合,需要使用 Filter Aggreagtion 只能进行多次请求。而使用 Filters Aggreagation 就可以解决上述的问题,它可以指定多个过滤条件,也是说可以对多个特定值进行聚合。
3.1过滤获取goodType为手机数码的桶,并求该桶平均值
{
"aggs" : {
"goodType_select_one" : {
"filter" : { "term": { "goodType": "手机数码" } },
"aggs" : {
"avg_price" : { "avg" : { "field" : "goodPrice" }
}
}
}
}
}
运行结果
3.2过滤获取goodType为手机数码或者goodName为男士外套的桶
- 多过滤器与单过滤器的作用类似,只是包含有多个过滤器,所以会形成多个桶。多过滤博型聚集使用filters参数接收过滤条件的数组,一般也是与指标聚集一同使用
{
"aggs":{
"buckets":{
"filters":{
"filters":{
"goodNameBucket":{
"match":{
"goodName":"男士外套"
}
},
"goodTypeBucket":{
"match":{
"goodType":"手机数码"
}
}
}
}
}
}
}
运行结果
Histogram Aggregation(直方图聚合)
概念:基于多桶值源的聚合,可应用于从文档中提取的数值或数值范围值。它动态地在值上构建固定大小(又名间隔)的桶。例如,如果文档有一个包含价格(数字)的字段,我们可以配置此聚合以动态构建具有间隔的存储桶5(在价格的情况下,它可能代表 5 美元)。当聚合执行时,每个文档的 price 字段将被评估,并将向下舍入到最接近的存储桶 - 例如,如果价格是32,存储桶大小是,5则舍入将产生30,因此文档将“落入”与 key 关联的存储桶30
4.1根据价格区间为10000分桶,同时如果桶中没有文档就不显示桶
最小文件数(指定匹配的桶中至少含有的文档数目):min_doc_count
{
"aggs":{
"histogram_goodPrice_10000":{
"histogram":{ //聚合的类型
"field":"goodPrice", //对该字段进行分组
"interval":"10000", //间隔为10000
"min_doc_count":1 //返回的桶里面至少有1个文档
}
}
}
}
运行结果
POST /kibana_sample_data_flights/_search?filter_path=aggregations
{
"aggs": {
"price_histo": {
"histogram": {
"field": "AvgTicketPrice",
"interval": 100,
"offset": 50,
"keyed": true,
"order": {
"_count": "asc"
}
}
}
}
}
- 其中,interval参数用于指定数值问隔必须为正值,而offset参数则代表起始数值的偏移量,必须位于[0, interval) 范围内。order参数用于指定排序字段和顺序,可选字段为_key和_count。
- 如果没有设置offset:100,200,300......;如果没有设置offset为50:50,100,150......
- 当keyed参数设置为true时,返回结果中每个桶会有一个标识,标识的计算公式为:
- bucket_key = Math. floor( ( value- offset)/interval) * interval + offset。
Range Aggregation (范围聚合)
用户自定义一组范围,每个范围代表一个桶.在聚合过程中,将从每个文档中提取的值根据每个存储区范围进行检查,并将相关/匹配文档“存储”到每个桶内.此聚合包括每个范围的from值并排除该to值
{
"aggs":{
"goodPrice_range":{ //聚合名字(自定义)
"range":{ //聚合类型
"field":"goodPrice", //该字段进行分组
"ranges":[ //自定义分组范围
{
"to":"89" //[*-89.0) 排除89
},
{
"from":"89", //[89-4000000) 排除4000000
"to":"4000000"
},
{
"from":"4000000" //[4000000-*)
}
]
}
}
}
}
运行结果
可以为每个范围自定义键
{
"aggs":{
"goodPrice_range":{
"range":{
"field":"goodPrice",
"ranges":[
{
"key":"group1",
"to":"89"
},
{
"key":"group2",
"from":"89",
"to":"4000000"
},
{
"key":"group3",
"from":"4000000"
}
]
}
}
}
}
运行结果
将文档“存储”到不同的存储桶中,并且计算每个价格范围内的价格统计信息
{
"aggs":{
"groupby_goodPrice":{
"range":{ //进行分组
"field":"goodPrice", //字段为goodPrice
"ranges":[
{
"key":"group1",
"to":"100"
},
{
"key":"group2",
"from":"100",
"to":"4000000"
},
{
"key":"group3",
"from":"4000000"
}
]
},
"aggs":{ //对分桶后的每个桶执行聚合操作
"goodPrice_stats":{
"stats":{
"field":"goodPrice"
}
}
}
}
}
}
运行结果
Date Histogram Aggregation(日期聚合)
Date Histogram Aggregation(日期直方图聚合): 类似于普通的 histogram,但它只能与日期或日期范围值一起使用;像直方图,数值四舍五入下来到最接近的水桶。例如,如果间隔是一个日历日,2020-01-03T07:00:01Z则四舍五入为 2020-01-03T00:00:00Z
日历间隔:
使用calendar_interval参数配置毫秒:1ms 10ms
秒:second/1s 10s
分钟:minute/1m 10m
小时:hout/1h 2h
天:day 2d 不支持
星期:week/1w 不支持
月:month/1M 不支持
季度:quarter/1q 不支持
年:year/1y 不支持
固定间隔
通过fixed_interval参数配置。
固定间隔的可接受单位是:毫秒 ( ms)--秒 ( s)--分钟 ( m)--小时 ( h)--天 ( d)
不过这个参数将要过期,替代的是fixed_interval和calendar_interval,可以参考这个页面,有详细说明:
Date histogram aggregation | Elasticsearch Guide [8.2] | Elastic
简单来说,calendar_interval支持1年、1季度、1月、1周、1天、1小时、1分钟,不支持时间为复数,fixed_interval支持的时间单位为天、小时、分、秒、毫秒,允许复数,例如"fixed_interval" : "30d",表示为30天。
{
"aggs" : {
"sales_time" : {
"date_histogram" : {
"field" : "sellTime",
"interval" : "1M",
"format" : "yyyy-MM-dd"
}
}
}
}
#interval指定时间间隔为month,即按月划分范围
POST /kibana_sample_data_flights/_search?filter_path=aggregations
{
"aggs": {
"month flights": {
"date_histogram": {
"field": "timestamp",
"interval": "month"
}
}
}
}
Demo
POST /kibana_sample_data_flights/_search { "size": 0, "aggs": { "sales": { "date_histogram": { "field": "timestamp", "interval": "month", "format": "yyyy-MM-dd" } } } }
从上面的结果分析,我们缺失了几个月,默认情况下,date_histogram(以及histogram)只会返回文档数量大于0的桶
我们需要返回所有的桶,哪怕其中不含有任何文档。我们可以设置两个额外的参数来实现这一行为
POST /kibana_sample_data_flights/_search { "size": 0, "aggs": { "sales": { "date_histogram": { "field": "timestamp", "interval": "month", "format": "yyyy-MM-dd", "min_doc_count": 0, "extended_bounds": { "min" : "2022-01-01", "max" : "2022-12-31" } } } } }以上的min_doc_count参数会强制返回空桶,extended_bounds参数会强制返回一整年的数据。
这两个参数会强制返回该年中的所有月份,无论它们的文档数量是多少。min_doc_count的意思很容易懂:它强制返回哪怕为空的桶。
extended_bounds参数需要一些解释。min_doc_count会强制返回空桶,但是默认ES只会返回在你的数据中的最小值和最大值之间的桶。
因此如果你的数据分布在四月到七月,你得到的桶只会表示四月到七月中的几个月(可能为空,如果使用了min_doc_count=0)。为了得到一整年的桶,我们需要告诉ES需要得到的桶的范围(如果文档中timestamp字段的最大值⼩于2022-12-31,那么统计到2022-12-31,若⼤于这
个2022-12-31的值,则⼀直聚合查询到⽂档中的最⼤值;如果文档中timestamp字段的最小值大于2022-12-31,那么从2022-01-01开始统计,若小于这
个2022-12-31的值,则从文档中timestamp字段最小值开始聚合)注意上⾯写的查询中的extended_bounds中的max不是指查询到这个最⼤值,⽽是如果⽂档中的最⼤值⼩于此,那么统计到此,若⼤于这
个max的值,则⼀直聚合查询到⽂档中的最⼤值
Date Range Arrgegation
Date Range Aggregation(日期范围聚合):专用于日期值的范围聚合。此聚合与正常范围 聚合之间的主要区别在于 ,from和to值可以用 日期数学表达式表示,并且还可以指定返回from和to响应字段的日期格式。请注意,此聚合包括每个范围的from值并排除该to值。
{
"aggs": {
"range": {
"date_range": {
"field": "sellTime",
"format": "MM-yyyy",
"ranges": [
{ "to": "now-10M/M" },
{ "from": "now-10M/M" }
]
}
}
}
}
auto_date_histogram聚集
- 前述两种聚集都是指定间隔的具体值是多少,然后再根据间隔值返回每一桶中满足条件的文档数。最终会有多少桶取决于两个条件,即间隔值和字段值在所有文档中的实际跨度。反过来,如果预先指定需要返回多少个桶,那么间隔值 也可以通过桶的数量以及字段值跨度共同确定。auto_date_histogram聚集就是这 样一种聚集,它不是指定时间间隔值,而是指定需要返回桶的数量。例如在示例 中定义需要返回10个时间段的桶:
POST /kibana_sample_data_flights/_search?size=0
- 参数field设置通过哪一个字段做时间分隔,而参数buckets则指明了需要返回多少个桶。 默认情况下, buckets的数量为10。需要注意的是,buckets只是设置了期望返回桶的数量,但实际返回桶的数量可能等于也可能小于buckets设置的值。例如示例的请求中期望10个桶,但实际可能只返回6个桶。
- auto_date_histogram聚集在返回结果中还提供了一个interval字段,用于说明实际采用的间隔时间。从实现的角度来说,不精确匹配buckets数量也有利于提升检索的性能。
ip Aggregation(ip聚合)
Elasticsearch还具有对IP范围
的内置支持。 IP聚合的工作方式与其他范围聚合类似。 让我们为IP地址创建索引映射,以说明此聚合的工作方式:
PUT ips
{
"mappings": {
"properties": {
"ip_addr": {
"type": "ip"
}
}
}
}
POST ips/_bulk
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.0" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.1" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.2" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.3" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.4" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.5" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.6" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.7" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.8" }
{"index":{"_index":"ips"}}
{ "ip_addr": "172.16.0.9" }
当索引中包含一些数据时,让我们创建一个IP范围聚合:
GET ips/_search
{
"size": 0,
"aggs": {
"ip_ranges": {
"ip_range": {
"field": "ip_addr",
"ranges": [
{
"to": "172.16.0.4"
},
{
"from": "172.16.0.4"
}
]
}
}
}
}
返回结果
"aggregations" : {
"ip_ranges" : {
"buckets" : [
{
"key" : "*-172.16.0.4",
"to" : "172.16.0.4",
"doc_count" : 4
},
{
"key" : "172.16.0.4-*",
"from" : "172.16.0.4",
"doc_count" : 6
}
]
}
}
global聚集
- global桶型聚集也是一种单桶型聚集, 它的作用是把索引中所有文档归入一个桶中。这种桶型聚集看似没有什么价值,但当global桶型聚集与query结合起来使用时,它不会受query定义的查询条件影响,最终形成的桶中仍然包含所有文档。global聚集在使用上非常简单,没有任何参数,例如:
POST /kibana_sample_data_flights/_search?size=0&filter_path=aggregations
{
"query": {
"term": {
"Carrier": {
"value": "Kibana Airlines"
}
}
},
"aggs": {
"kibana_avg_delay": {
"avg": {
"field": "FlightDelayMin"
}
},
"all flights": {
"global": {},
"aggs": {
"all_avg_delay": {
"avg": {
"field": "FlightDelayMin"
}
}
}
}
}
}
- 在示例中query使用term查询将航空公司为“Kibana Airline"的文档都检索出来,而kibana _avg delay定义的平均值聚集会将它们延误时间的平均值计算出来。但另个all_fights聚集由于使用了global聚集所以在嵌套的all_avg_delay聚集中计算出来的是所有航班廷误时间的平均值。
missing聚集
- missing聚集同样也是一种单桶型聚集,它的作用是将某一字段缺失的文档归入一桶。missing聚集使用field参数定义要检查缺失的字段名称,例如:
POST /kibana_sample_data_flights/_search?filter_path=aggregations
{
"aggs": {
"no_price": {
"missing": {
"field": "AvgTicketPrice"
}
}
}
}
- 示例将kibana_sample_data_flights中缺失AvgTicketPrice字段的文档归入一桶,通过返回结果的doc_count查询数量也可以与指标聚集做嵌套,计算这些文档的某一指标值。
聚集组合
有两种比较特殊的多桶型聚集,它们是composite聚集和adjacency_matrix聚集。这两种聚集是以组合不同条件的形式形成新桶,只是在组合的方法和组件 的条件上存在着明显差异。
composite聚集可以将不同类型的聚集组合到一一起,它会从不同的聚集中 提取数据,并以笛卡尔乘积的形式组合它们,而每一个组合就会形成一个新桶。 例如想查看平均票价与机场天气的对应关系,可以这样:
POST /kibana_sample_data_flights/_search?filter_path=aggregations
{
"aggs": {
"price_weather": {
"composite": {
"sources": [
{
"avg_price": {
"histogram": {
"field": "AvgTicketPrice",
"interval": 50
}
}
},
{
"weather": {
"terms": {
"field": "OriginWeather"
}
}
}
]
}
}
}
}
在示例中,composite聚集中通过soures参数定义了两个需要组合的子聚集。第一个聚集avg_price是一个针对AvgTicketPrice以50为间隔的histogam聚集,第二个则聚集weather则一个针对OriginWeather的terms聚集。sources参数中还可以定义更多的聚集,它们会以笛卡儿乘积的形式组合起来。在返回结果中除了由各聚集组合形成的桶以外,还有一个after_key字段:
{
"aggregations" : {
"price_weather" : {
"after_key" : {
"avg_price" : 500.0,
"weather" : "Cloudy"
},
"buckets" : [
{
"key" : {
"avg_price" : 0.0,
"weather" : "Clear"
},
"doc_count" : 795
},
{
"key" : {
"avg_price" : 0.0,
"weather" : "Cloudy"
},
"doc_count" : 809
},
{
"key" : {
"avg_price" : 500.0,
"weather" : "Cloudy"
},
"doc_count" : 1365
}
]
}
}
}
它包含自前聚集结果中最后一个结果的key。所以请求下一页聚集结果就可以通过after和size参数值定,例如:
POST /kibana_sample_data_flights/_search?filter_path=aggregations
{
"aggs": {
"price_weather": {
"composite": {
"after": {
"avg_price": 500,
"weather": "Cloudy"
},
"sources": [
{
"avg_price": {
"histogram": {
"field": "AvgTicketPrice",
"interval": 500
}
}
},
{
"weather": {
"terms": {
"field": "OriginWeather"
}
}
}
]
}
}
}
}