在數(shù)據(jù)庫領(lǐng)域,借助SQL我們可以獲取表中的最大值(Max)、最小值(Min),還可以對數(shù)據(jù)進行分組(Group)。在ES中使用聚合(Aggregations)來實現(xiàn)類似的功能,而且比SQL更靈活、更強大。
ES 7中,將聚合分為四類:
-
指標聚合(Metrics Aggregations): 一些數(shù)學運算,可以對文檔字段進行統(tǒng)計分析,如計算最大值、最小值、平均值等,類似于SQL中的
COUNT()、SUM()、MAX()等統(tǒng)計方法 -
桶聚合(Bucket Aggregations): 滿足特定條件的文檔分組,類似SQL中的
GROUP BY - 管道聚合(Pipeline Aggregations): 管道分析類型,基于上一級的聚合分析結(jié)果進行在分析,工作在其他聚合計算結(jié)果而不是文檔集合的聚合
- 矩陣聚合(Matrix Aggregations): 操作多個字段并根據(jù)從請求的文檔字段中提取的值生成矩陣結(jié)果
實際開發(fā)中,指標聚合和桶聚合用途很廣泛,而管道聚合和矩陣聚合是帶有實驗性質(zhì)的功能,很少使用。
1、指標聚合
按照輸出結(jié)果的數(shù)量,指標聚合可以分為兩類:
-
單值分析,只輸出一個分析結(jié)果:
- Min:最小值
- Max:最大值
- Avg:平均值
- Sum:累加值
- Cardinality:不同數(shù)值的個數(shù),相當于 SQL 中的 distinct
-
多值分析,輸出多個分析結(jié)果:
- Stats:樣的數(shù)據(jù)分析,可以一次性得到最大值、最小值、平均值、中值等數(shù)據(jù)
- Extended Stats:是對 Stats 的擴展,包含了更多的統(tǒng)計數(shù)據(jù),比如方差、標準差等
- Percentiles:按從小到大累計每個值對應的文檔數(shù)的占比,返回指定占比比例對應的值
- Percentile Ranks:Percentiles是通過百分比求文檔值,Percentile Ranks是通過文檔值求百分比
- Top Hits:一般用于分桶后獲取桶內(nèi)最匹配的頂部文檔列表
計算最大值:
{
"aggs":{
"max_price":{
"max":{
"field":"price"
}
}
}
}
可以與query結(jié)合使用,比如先過濾,再求和:
{
"query":{
"constant_score":{
"filter":{
"match":{
"type":"hat"
}
}
}
},
"aggs":{
"hat_prices":{
"sum":{
"field":"price"
}
}
}
}
再來看一下Percentiles與Percentile Ranks的用法。假如有一批消費者數(shù)據(jù),其中有一個字段記錄了日均消費金額,現(xiàn)在想知道日均消費金額的分布占比情況:
{
"size":0,
"aggs":{
"money_stat":{
"percentiles":{
"field":"money"
}
}
}
}
返回結(jié)果:
{
...
"aggregations": {
"money_stat": {
"values" : {
"1.0": 5.0,
"5.0": 25.0,
"25.0": 165.0,
"50.0": 445.0,
"75.0": 725.0,
"95.0": 945.0,
"99.0": 985.0
}
}
}
}
默認按照[ 1, 5, 25, 50, 75, 95, 99 ]來統(tǒng)計。
統(tǒng)計結(jié)果反映:1%的人消費金額在5元以內(nèi)、5%的人消費金額在25元以內(nèi)......95%的人消費金額在945元以內(nèi)、99%的人消費金額在985元以內(nèi)。
如果想知道日均消費金額在500以內(nèi)以及600以內(nèi)的人群占比是多少呢?可以使用Percentile Ranks來統(tǒng)計:
{
"size":0,
"aggs":{
"money_ranks":{
"percentile_ranks":{
"field":"money",
"values":[
500,
600
]
}
}
}
}
返回結(jié)果:
{
...
"aggregations": {
"load_time_ranks": {
"values" : {
"500.0": 55.1,
"600.0": 64.0
}
}
}
}
統(tǒng)計結(jié)果反映:日均消費金額在500以內(nèi)比為55.1%,日均消費金額在600以內(nèi)的人群占比為64%。
結(jié)合桶聚合,還可以更復雜的統(tǒng)計,例如,根據(jù)工作類型分桶,然后按照性別分桶,計算每個桶中工資的最高的薪資:
{
"size":0,
"aggs":{
"Job_gender_stats":{
"terms":{
"field":"job.keyword"
},
"aggs":{
"gender_stats":{
"terms":{
"field":"gender"
},
"aggs":{
"salary_stats":{
"max":{
"field":"salary"
}
}
}
}
}
}
}
}
返回結(jié)果:

2、桶聚合
準備一組汽車銷售數(shù)據(jù)用于測試,包含汽車的價格、顏色、品牌、銷售時間:
POST /cars/_bulk
{ "index": {}}
{ "price" : 80000, "color" : "red", "brand" : "BMW", "sellTime" : "2014-01-28" }
{ "index": {}}
{ "price" : 85000, "color" : "green", "brand" : "BMW", "sellTime" : "2014-02-05" }
{ "index": {}}
{ "price" : 120000, "color" : "green", "brand" : "Mercedes", "sellTime" : "2014-03-18" }
{ "index": {}}
{ "price" : 105000, "color" : "blue", "brand" : "Mercedes", "sellTime" : "2014-04-02" }
{ "index": {}}
{ "price" : 72000, "color" : "green", "brand" : "Audi", "sellTime" : "2014-05-19" }
{ "index": {}}
{ "price" : 60000, "color" : "red", "brand" : "Audi", "sellTime" : "2014-06-05" }
{ "index": {}}
{ "price" : 40000, "color" : "red", "brand" : "Audi", "sellTime" : "2014-07-01" }
{ "index": {}}
{ "price" : 35000, "color" : "blue", "brand" : "Honda", "sellTime" : "2014-08-12" }
3、查看是否成功
2.1 Terms Aggregation
基于某個field,該 field 內(nèi)的每一個唯一詞元為一個桶,并計算每個桶內(nèi)文檔個數(shù)。默認返回順序是按照文檔個數(shù)多少排序。需要注意的是,生產(chǎn)環(huán)境中數(shù)據(jù)一般是分布在多個分片上,當不返回所有 buckets 時(由size控制),文檔個數(shù)可能不準確。
按照汽車品牌聚合,按照數(shù)量排序,只返回前三名:
{
"aggs":{
"genres":{
"terms":{
"field":"brand",
"order":{
"_count":"asc"
},
"size":3
}
}
}
}
返回結(jié)果:

2.2 Filter Aggregation
Terms Aggregation 的基礎(chǔ)上進行了過濾,只對特定的值進行了聚合。
過濾獲取品牌為BMW的桶,并求該桶平均值:
{
"aggs":{
"brands":{
"filter":{
"term":{
"brand":"BMW"
}
},
"aggs":{
"avg_price":{
"avg":{
"field":"price"
}
}
}
}
}
}
返回結(jié)果:

如果想要指定多個過濾條件,可以使用Filters Aggreagation:
{
"size":0,
"aggs":{
"cars":{
"filters":{
"filters":{
"colorBucket":{
"match":{
"color":"red"
}
},
"brandBucket":{
"match":{
"brand":"Audi"
}
}
}
}
}
}
}
返回結(jié)果:

2.3 Histogram Aggreagtion
直方圖聚合,與Terms聚合類似,都是數(shù)據(jù)分組,區(qū)別是Terms是按照Field的值分組,而Histogram可以按照指定的間隔對Field進行分組。
根據(jù)價格區(qū)間為10000分桶:
{
"aggs":{
"prices":{
"histogram":{
"field":"price",
"interval":10000
}
}
}
}
返回結(jié)果:

2.4 Range Aggregation
范圍聚合,根據(jù)用戶傳遞的范圍參數(shù)作為桶,進行相應的聚合。在同一個請求中,可以傳遞多組范圍,每組范圍作為一個桶。
根據(jù)價格區(qū)間分桶:
{
"aggs":{
"price_ranges":{
"range":{
"field":"price",
"ranges":[
{
"to":50000
},
{
"from":5000,
"to":80000
},
{
"from":80000
}
]
}
}
}
}
返回結(jié)果:

2.5 Nested Aggregation
一個特殊的single bucket(單桶)聚合,可以聚合嵌套的文檔
例如,假設(shè)我們有一個產(chǎn)品的索引,并且每個產(chǎn)品都包含一個分銷商列表——每個產(chǎn)品都有自己的價格。映射可能是:
{
...
"product" : {
"properties" : {
"resellers" : { #1
"type" : "nested",
"properties" : {
"name" : { "type" : "text" },
"price" : { "type" : "double" }
}
}
}
}
}
resellers是一個在product對象下保存嵌套文檔的數(shù)組。
以下匯總將返回可以購買的最低價格產(chǎn)品:
{
"query" : {
"match" : { "name" : "led tv" }
},
"aggs" : {
"resellers" : {
"nested" : {
"path" : "resellers"
},
"aggs" : {
"min_price" : { "min" : { "field" : "resellers.price" } }
}
}
}
}
如上所述,嵌套聚合需要頂層文檔中嵌套文檔的路徑。 然后可以在這些嵌套文檔上定義任何類型的聚合。
響應結(jié)果:
{
"aggregations": {
"resellers": {
"min_price": {
"value" : 350
}
}
}