- ES聚合查詢流程
- 核心概念
2.1 桶
2.2 指標 - ES聚合查詢的語法
3.1 聚合查詢的size語法 - 指標聚合
4.1 value count
4.2 Cardinality
4.3 avg sum max min
4.4 綜合例子 - 分組聚合查詢(bucket)
5.1 Terms聚合
5.2 Histogram聚合
5.3 Date histogram聚合
5.4 Range聚合
5.5 混合使用 - 多桶排序
6.1 多桶排序
--6.1.1 內置排序
--6.1.2 按度量排序
6.2 限制返回桶的數量
推薦閱讀
ES的聚合查詢,類似SQL中sum/avg/count/group by分組查詢,主要用于統計分析
1. ES聚合查詢流程
ES聚合查詢類似SQL的group by,一般統計分析主要分為兩個步驟:
- group by分組
- 組內聚合
對查詢的數據一般先進行分組,可以設置分組條件。然后將組內的數據進行聚合統計。
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>:聚合類型的參數,選擇不同的聚合類型,又不同的參數。
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
值聚合,主要用于統計文檔總數。
如上圖所示:得到的總數為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"
}
}
}
}
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作用一致,都是根據字段唯一值對數據進行分組(分桶),字段值相等的文檔都分到同一個桶內。
5.2 Histogram聚合
histogram(直方圖)聚合,只要根據數值間隔分組,使用histogram聚合分組統計結果,通常用在繪制條形圖報表。
POST test_len/_search?size=0
{
"aggs" : {
"prices" : { // 聚合查詢名字,隨便取一個
"histogram" : { // 聚合類型為:histogram
"field" : "price", // 根據price字段分桶
"interval" : 50 // 分桶的間隔為50,意思就是price字段值按50間隔分組
}
}
}
}
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 }
]
}
}
}
}
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個桶
}
}
}
}