es7.x(10)aggs聚合查詢

  1. ES聚合查詢流程
  2. 核心概念
    2.1 桶
    2.2 指標
  3. ES聚合查詢的語法
    3.1 聚合查詢的size語法
  4. 指標聚合
    4.1 value count
    4.2 Cardinality
    4.3 avg sum max min
    4.4 綜合例子
  5. 分組聚合查詢(bucket)
    5.1 Terms聚合
    5.2 Histogram聚合
    5.3 Date histogram聚合
    5.4 Range聚合
    5.5 混合使用
  6. 多桶排序
    6.1 多桶排序
    --6.1.1 內置排序
    --6.1.2 按度量排序
    6.2 限制返回桶的數量
    推薦閱讀

ES的聚合查詢,類似SQL中sum/avg/count/group by分組查詢,主要用于統計分析

1. ES聚合查詢流程

ES聚合查詢類似SQL的group by,一般統計分析主要分為兩個步驟:

  1. group by分組
  2. 組內聚合

對查詢的數據一般先進行分組,可以設置分組條件。然后將組內的數據進行聚合統計。

2. 核心概念

2.1 桶

滿足特定條件的文檔集合,叫做桶。

桶的就是一組數據的集合,數據分組后,得到一組組的數據,就是一組組的桶。

桶等同于組,分桶和分組是一個意思。

ES中桶聚合,指的就是先對數據進行分組,ES支持多種分組條件。

2.2 指標

指標指的是對文檔進行統計計算的方式,又稱指標聚合。

桶內聚合:就是對數據先進行分組(分桶),然后對每一個桶內的數據進行指標聚合。

常見的指標有:sum/count/max/min等統計函數。

3. ES聚合查詢的語法

{
  "aggregations" : {  (1)
    "<aggregation_name>" : {  (2)
        "<aggregation_type>" : { (3)
            <aggregation_body>   (4)
        }
        [,"aggregations" : { [<sub_aggregation>]+ } ]? // 嵌套聚合查詢,支持多層嵌套
    }
    [,"<aggregation_name_2>" : { ... } ]* // 多個聚合查詢,每個聚合查詢取不同的名字
  }
}

(1) aggregations :代表聚合查詢語句,可以簡寫為aggs;
(2)<aggregation_name>:代表一個聚合計算的銘記,可以隨意命名,因為ES支持一次進行多次的統計分析查詢,后面需要通過這個名字在查詢結果中找到我們想要的結果;
(3)<aggregation_type>:聚合類型,代表我們想要怎么統計數據。主要有兩大類的聚合類型:桶聚合和指標聚合,這兩類又包括多種聚合類型,例如:指標聚合:sum/count。桶聚合:terms、Date、histogram等。
(4)<aggregation_body>:聚合類型的參數,選擇不同的聚合類型,又不同的參數。

image.png

3.1 聚合查詢的size語法

size=0代表不需要返回query查詢結果,僅僅返回aggs統計結果

GET test_len/_search
{
  "size": 0, 
  "aggs": {
    "prices": {
      "date_histogram": {
        "field": "p_date",
        "calendar_interval":"month",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

4. 指標聚合

ES指標聚合,就是類型SQL的統計函數,指標聚合可以單獨使用,也可以和桶聚合一起使用。

常用的統計函數:

  • value count:統計總數;
  • Cardinality:類似SQL的count(DISTINCT 字段), 統計不重復的數據總數
  • avg:平均值
  • sum:求和
  • max:最大值
  • min:最小值

4.1 value count

值聚合,主要用于統計文檔總數。

image.png
image.png

如上圖所示:得到的總數為2個文檔。

GET test_len/_search
{
  "aggs": {
    "price_count": {   //名字隨便起,聚合查詢的名字
      "value_count": {    //聚合查詢的類型
        "field": "price"  //計算price這個字段的總數
      }
    }
  }
}

4.2 Cardinality

基數聚合,也是用于統計文檔的總數,跟value Count的區別是:基數聚合會去重,不會統計重復的值,類似SQL的count(distinct 字段)的用法。

注意:前面提到基數聚合的作用等價于SQL的count(DISTINCT 字段)的用法,其實不太準確,因為SQL的count統計結果是精確統計不會丟失精度,但是ES的cardinality基數聚合統計的總數是一個近似值,會有一定的誤差,這么做的目的是為了性能,因為在海量的數據中精確統計總數是非常消耗性能的,但是很多業務場景不需要精確的結果,只要近似值,例如:統計網站一天的訪問量,有點誤差沒關系。

4.3 avg sum max min

avg:求平均值
sum:求和
max:求最大值
min:求最小值

4.4 綜合例子

前面的例子,僅僅介紹聚合指標的單獨使用的情況,實際應用中經常先通過query查詢,搜索索引中的數據,然后對query查詢結果進行統計分析。

GET test_len/_search
{
  "query": {
    "term": {
      "p_type": {
        "value": "vip"
      }
    }
  },
  "aggs": {
    "sum_price": {
      "sum": {
        "field": "price" 
      }
    },
    "min_price":{
      "min": {
        "field": "price"
      }
    }
  }
}
image.png

5. 分組聚合查詢(bucket)

Elasticsearch桶聚合,目的就是數據分組,先將數據按指定的條件分成多個組,然后對每一個組進行統計。 組的概念跟桶是等同的,在ES中統一使用桶(bucket)這個術語。

ES桶聚合的作用跟sql的group by作用是一樣的,區別是ES支持更加強大的數據分組能力,SQL只能根據字段的唯一值進行分組,分組的數量跟字段的唯一值的數量相等,例如: group by 店鋪id, 去掉重復的店鋪ID后,有多少個店鋪就有多少個分組。

ES常用的桶聚合如下:

  • terms聚合:類似sql的group by,根據字段唯一值分組;
  • Histogram(柱狀圖, [?h?st?ɡr?m])聚合:根據數組間隔分組,例如:價格100間隔分組,0,100,200等等;
  • Date histogram聚合:根據時間間隔分組,例如:按月、天、小時分組;
  • Range聚合:按數值范圍,例如0-150、150-200一組,200-500一組。

桶聚合一般不單獨使用,都是配合指標聚合一起使用,對數據分組之后肯定要統計桶內數據,在ES中如果沒有明確指定指標聚合,默認使用Value Count指標聚合,統計桶內文檔總數。

5.1 Terms聚合

terms聚合的作用跟sql中的group by作用一致,都是根據字段唯一值對數據進行分組(分桶),字段值相等的文檔都分到同一個桶內。

image.png

5.2 Histogram聚合

histogram(直方圖)聚合,只要根據數值間隔分組,使用histogram聚合分組統計結果,通常用在繪制條形圖報表。

POST test_len/_search?size=0
{
    "aggs" : {
        "prices" : { // 聚合查詢名字,隨便取一個
            "histogram" : { // 聚合類型為:histogram
                "field" : "price", // 根據price字段分桶
                "interval" : 50 // 分桶的間隔為50,意思就是price字段值按50間隔分組
            }
        }
    }
}
image.png

5.3 Date histogram聚合

類似histogram聚合,區別是Date histogram可以很好的處理時間類型字段,主要用于根據時間、日期分桶的場景。

POST /sales/_search?size=0
{
    "aggs" : {
        "sales_over_time" : { // 聚合查詢名字,隨便取一個
            "date_histogram" : { // 聚合類型為: date_histogram
                "field" : "date", // 根據date字段分組
                "calendar_interval" : "month", // 分組間隔:month代表每月、支持minute(每分鐘)、hour(每小時)、day(每天)、week(每周)、year(每年)
                "format" : "yyyy-MM-dd" // 設置返回結果中桶key的時間格式
            }
        }
    }
}

返回結果:

{
    ...
    "aggregations": {
        "sales_over_time": { // 聚合查詢名字
            "buckets": [ // 桶聚合結果
                {
                    "key_as_string": "2015-01-01", // 每個桶key的字符串標識,格式由format指定
                    "key": 1420070400000, // key的具體字段值
                    "doc_count": 3 // 默認按Value Count指標聚合,統計桶內文檔總數
                },
                {
                    "key_as_string": "2015-02-01",
                    "key": 1422748800000,
                    "doc_count": 2
                },
                {
                    "key_as_string": "2015-03-01",
                    "key": 1425168000000,
                    "doc_count": 2
                }
            ]
        }
    }
}

5.4 Range聚合

GET /_search
{
    "aggs" : {
        "price_ranges" : { // 聚合查詢名字,隨便取一個
            "range" : { // 聚合類型為: range
                "field" : "price", // 根據price字段分桶
                "ranges" : [ // 范圍配置
                    { "to" : 100.0 }, // 意思就是 price < 100的文檔歸類到一個桶
                    { "from" : 100.0, "to" : 200.0 }, // price>=100 and price<200的文檔歸類到一個桶
                    { "from" : 200.0 } // price>=200的文檔歸類到一個桶
                ]
            }
        }
    }
}

返回結果:

{
    ...
    "aggregations": {
        "price_ranges" : { // 聚合查詢名字
            "buckets": [ // 桶聚合結果
                {
                    "key": "*-100.0", // key可以表達分桶的范圍
                    "to": 100.0, // 結束值
                    "doc_count": 2 // 默認按Value Count指標聚合,統計桶內文檔總數
                },
                {
                    "key": "100.0-200.0",
                    "from": 100.0, // 起始值
                    "to": 200.0, // 結束值
                    "doc_count": 2
                },
                {
                    "key": "200.0-*",
                    "from": 200.0,
                    "doc_count": 3
                }
            ]
        }
    }
}

可以發現,range分桶,默認key的值不友好。尤其是開發的時候,不知道key是什么樣子,處理比較麻煩,可以為每一個分桶指定一個有意義的名字。

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "keyed" : true,
                "ranges" : [
                    // 通過key參數,配置每一個分桶的名字
                    { "key" : "cheap", "to" : 100 },
                    { "key" : "average", "from" : 100, "to" : 200 },
                    { "key" : "expensive", "from" : 200 }
                ]
            }
        }
    }
}
image.png

5.5 混合使用

實際開發中,經常需要配合query語句,先搜索目標文檔,然后使用aggs聚合語句對搜索結果進行統計分析。

聚合查詢支持多層嵌套。

GET /cars/_search
{
    "size": 0, // size=0代表不需要返回query查詢結果,僅僅返回aggs統計結果
    "query" : { // 設置查詢語句,先賽選文檔
        "match" : {
            "make" : "ford"
        }
    },
    "aggs" : { // 然后對query搜索的結果,進行統計
        "colors" : { // 聚合查詢名字
            "terms" : { // 聚合類型為:terms 先分桶
              "field" : "color"
            },
            "aggs": { // 通過嵌套聚合查詢,設置桶內指標聚合條件
              "avg_price": { // 聚合查詢名字
                "avg": { // 聚合類型為: avg指標聚合
                  "field": "price" // 根據price字段計算平均值
                }
              },
              "sum_price": { // 聚合查詢名字
                "sum": { // 聚合類型為: sum指標聚合
                  "field": "price" // 根據price字段求和
                }
              }
            }
        }
    }
}

6. 多桶排序

類似terms、histogram、date_histogram這類桶聚合都會動態生成多個桶,如果生成的桶特別多,我們如何確定這些桶的排序順序,如何限制返回桶的數量。

6.1 多桶排序

默認情況下,ES會根據doc_count文檔總數,降序排序。

ES桶聚合支持兩種方式排序:

  • 內置排序;
  • 按度量指標排序;

6.1.1 內置排序

內置排序參數:

  • _count :按文檔數排序,對terms、histogram、date_histogram有效;
  • _term:按次項的字符串值的字母順序排序,只在terms內使用;
  • _key:按每個桶的鍵值數值排序,僅對histogram和date_histogram有效;
GET /cars/_search
{
    "size" : 0,
    "aggs" : {
        "colors" : { // 聚合查詢名字,隨便取一個
            "terms" : { // 聚合類型為: terms
              "field" : "color", 
              "order": { // 設置排序參數
                "_count" : "asc"  // 根據_count排序,asc升序,desc降序
              }
            }
        }
    }
}

6.1.2 按度量排序

通常情況下,我們根據桶聚合分桶后,都會對桶內進行多個維度的指標聚合,所以我們也可以根據桶內指標聚合的結果進行排序。

GET /cars/_search
{
    "size" : 0,
    "aggs" : {
        "colors" : { // 聚合查詢名字
            "terms" : { // 聚合類型: terms,先分桶
              "field" : "color", // 分桶字段為color
              "order": { // 設置排序參數
                "avg_price" : "asc"  // 根據avg_price指標聚合結果,升序排序。
              }
            },
            "aggs": { // 嵌套聚合查詢,設置桶內聚合指標
                "avg_price": { // 聚合查詢名字,前面排序引用的就是這個名字
                    "avg": {"field": "price"} // 計算price字段平均值
                }
            }
        }
    }
}

6.2 限制返回桶的數量

如果分桶數量太多,可以通過給桶聚合增加一個size參數限制返回桶的數量。

GET /_search
{
    "aggs" : {
        "products" : { // 聚合查詢名字
            "terms" : { // 聚合類型為: terms
                "field" : "product", // 根據product字段分桶
                "size" : 5 // 限制最多返回5個桶
            }
        }
    }
}

推薦閱讀

Elasticsearch筆記(七):聚合查詢

Elasticsearch 聚合查詢(aggs)基本概念

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容