Elasticsearch(四) -- 聚合查询(Bucket)

目录

概念:Bucket可以理解为一个桶,符合要求的放入一个桶中,相当于mysql中的groupBy

一,创建索引数据,参考Elasticsearch(三)--Metric(指标)

Aggregation语法

Terms Aggregation (术语聚合)

Bucket size & Top hits Demo

 Filter Aggregation(过滤聚合)

3.1过滤获取goodType为手机数码的桶,并求该桶平均值

 3.2过滤获取goodType为手机数码或者goodName为男士外套的桶

 Histogram Aggregation(直方图聚合)

 4.1根据价格区间为10000分桶,同时如果桶中没有文档就不显示桶

 Range Aggregation (范围聚合)

 Date Histogram Aggregation(日期聚合)

Demo

Date Range Arrgegation

auto_date_histogram聚集

ip Aggregation(ip聚合) 

global聚集

missing聚集

聚集组合


说明:该博客对应的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,按多值指标子聚合(由聚合名称标识)对存储桶进行排序

按单值指标子聚合(由聚合名称标识)对存储桶进行排序

POST   http://localhost:9200/goods/_search?size=0

{
    "aggs":{
        "term_goodType":{
            "terms":{
                "field":"goodType",
                //"size":3,
                "order":{
                    "in_bucket_max_goodPrice":"desc"  //对该聚合名称进行降序排序
                }
            },
        "aggs":{
            "in_bucket_max_goodPrice":{    //聚合名称的具体实现
                "max":{
                    "field":"goodPrice"
                }
            }
        }
        }
    }
}

 运行结果

按多值指标子聚合(由聚合名称标识)对存储桶进行排序

POST   http://localhost:9200/goods/_search?size=0

{
    "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为手机数码的桶,并求该桶平均值

POST   http://localhost:9200/goods/_search?size=0

{
    "aggs" : {
        "goodType_select_one" : {
            "filter" : { "term": { "goodType": "手机数码" } },
            "aggs" : {
                "avg_price" : { "avg" : { "field" : "goodPrice" } 
                }
            }
        }
    }
}

 运行结果

 3.2过滤获取goodType为手机数码或者goodName为男士外套的桶

  • 多过滤器与单过滤器的作用类似,只是包含有多个过滤器,所以会形成多个桶。多过滤博型聚集使用filters参数接收过滤条件的数组,一般也是与指标聚集一同使用

POST   http://localhost:9200/goods/_search?size=0

{
    "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值

POST    http://localhost:9200/goods/_search?size=0

{
    "aggs":{                     
        "goodPrice_range":{     //聚合名字(自定义)
            "range":{              //聚合类型
                "field":"goodPrice",      //该字段进行分组
                "ranges":[                 //自定义分组范围
                    {
                        "to":"89"          //[*-89.0) 排除89
                    },
                    {
                        "from":"89",          //[89-4000000)  排除4000000
                        "to":"4000000"
                    },
                    {
                        "from":"4000000"          //[4000000-*)
                    }
                ]
            }
        }
    }
}

运行结果

  

可以为每个范围自定义键

 POST    http://localhost:9200/goods/_search?size=0

{
    "aggs":{
        "goodPrice_range":{
            "range":{
                "field":"goodPrice",
                "ranges":[
                    {
                        "key":"group1",
                        "to":"89"
                    },
                    {
                        "key":"group2",
                        "from":"89",
                        "to":"4000000"
                    },
                    {
                        "key":"group3",
                        "from":"4000000"
                    }
                ]
            }
        }
    }
}

 运行结果

将文档“存储”到不同的存储桶中,并且计算每个价格范围内的价格统计信息 

 POST    http://localhost:9200/goods/_search?size=0

{
    "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

{

  "aggs": {

    "age_group": {

      "auto_date_histogram": {

        "field": "timestamp",

        "buckets": 10

      }

    }

  }

}

  • 参数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"

              }

            }

          }

        ]

      }

    }

  }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值