Elasticsearch之聚合查詢

在數(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é)果:

0.png

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é)果:

1.png

2.2 Filter Aggregation

Terms Aggregation 的基礎(chǔ)上進行了過濾,只對特定的值進行了聚合。

過濾獲取品牌為BMW的桶,并求該桶平均值:

{
    "aggs":{
        "brands":{
            "filter":{
                "term":{
                    "brand":"BMW"
                }
            },
            "aggs":{
                "avg_price":{
                    "avg":{
                        "field":"price"
                    }
                }
            }
        }
    }
}

返回結(jié)果:

2.png

如果想要指定多個過濾條件,可以使用Filters Aggreagation:

{
    "size":0,
    "aggs":{
        "cars":{
            "filters":{
                "filters":{
                    "colorBucket":{
                        "match":{
                            "color":"red"
                        }
                    },
                    "brandBucket":{
                        "match":{
                            "brand":"Audi"
                        }
                    }
                }
            }
        }
    }
}

返回結(jié)果:

3.png

2.3 Histogram Aggreagtion

直方圖聚合,與Terms聚合類似,都是數(shù)據(jù)分組,區(qū)別是Terms是按照Field的值分組,而Histogram可以按照指定的間隔對Field進行分組。

根據(jù)價格區(qū)間為10000分桶:

{
    "aggs":{
        "prices":{
            "histogram":{
                "field":"price",
                "interval":10000
            }
        }
    }
}

返回結(jié)果:

4.png

2.4 Range Aggregation

范圍聚合,根據(jù)用戶傳遞的范圍參數(shù)作為桶,進行相應的聚合。在同一個請求中,可以傳遞多組范圍,每組范圍作為一個桶。

根據(jù)價格區(qū)間分桶:

{
    "aggs":{
        "price_ranges":{
            "range":{
                "field":"price",
                "ranges":[
                    {
                        "to":50000
                    },
                    {
                        "from":5000,
                        "to":80000
                    },
                    {
                        "from":80000
                    }
                ]
            }
        }
    }
}

返回結(jié)果:

5.png

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
            }
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容