聚合查詢,它是在搜尋的結果上,提供的一些聚合資料資訊的方法。比如:求和、最大值、平均數等。聚合查詢的型別有很多種,每一種型別都有它自己的目的和輸出。在ES中,也有很多種聚合查詢,下面我們看看聚合查詢的語法結構,
"aggregations" : {
"<aggregation_name>" : {
"<aggregation_type>" : {
<aggregation_body>
}
[,"meta" : { [<meta_data_body>] } ]?
[,"aggregations" : { [<sub_aggregation>]+ } ]?
}
[,"<aggregation_name_2>" : { ... } ]*
}
aggregations
實體包含了所有的聚合查詢,如果是多個聚合查詢可以用陣列,如果只有一個聚合查詢使用物件,aggregations
也可以簡寫為aggs
。aggregations
裡邊的每一個聚合查詢都有一個邏輯名稱,這個名稱是使用者自定義的,在我們的語法結構中,對應的是<aggregation_name>
。比如我們的聚合查詢要計算平均價格,這時我們自定義的聚合查詢的名字就可以叫做avg_price
,這個名字要在聚合查詢中保持唯一。
在自定義的聚合查詢物件中,需要指定聚合查詢的型別,這個型別欄位往往是物件中的第一個欄位,在上面的語法結構中,對應的是<aggregation_type>
。在聚合查詢的內部,還可以有子聚合查詢,對應的是aggregations
,但是隻有Bucketing
型別的聚合查詢才可以有子聚合查詢。
metrics 聚合查詢
metrics 我覺得在這裡翻譯成“指標”比較好,也不是太準確,我們還是用英文比較好。metrics 聚合查詢的值都是從查詢結果中的某一個欄位(field)提煉出來的,下面我們就看看一些常用的metrics 聚合查詢。我們有如下的一些索引資料,大家先看一下,
索引的名字叫做bank
,一些關鍵的欄位有account_number
銀行賬號,balance
賬戶餘額,firstname
和lastname
等,大家可以直接看出它們代表的含義。假如我們想看看銀行裡所有人的平均餘額是多少,那麼查詢的語句該怎麼寫呢?
POST /bank/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
}
}
},
"aggs": {
"avg_balance": {
"avg": {
"field": "balance"
}
}
}
}
在查詢語句中,查詢的條件匹配的是全部,在聚合查詢中,我們自定義了一個avg_balance
的聚合查詢,它的型別是avg
,求平均數,然後我們指定欄位是balance
,也就是我們要計算平均數的欄位。我們執行一下,然後看看返回的結果,
{
"took": 11,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": ……
"aggregations": {
"avg_balance": {
"value": 25714.837
}
}
}
在返回的結果中,我們看到在aggregations
中,返回了我們自定義的聚合查詢avg_balance
,並且計算的平均值是25714.837
。
如果我們要查詢balance
的最大、最小、平均、求和、數量等,可以使用stats
查詢,我們來看一下如何傳送這個請求,
POST /bank/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
}
}
},
"aggs": {
"stats_balance": {
"stats": {
"field": "balance"
}
}
}
}
我們只需要把前面聚合查詢的型別改為stats
就可以了,我們看一下返回的結果,
{
"took": 20,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": ……
"aggregations": {
"stats_balance": {
"count": 1000,
"min": 1011,
"max": 49989,
"avg": 25714.837,
"sum": 25714837
}
}
}
我們可以看到在返回的結果中,返回了5個欄位,我們最常用的最大、最小、平均、求和、數量都包含在內,很方便是不是。
Bucket 聚合查詢
Bucket 聚合不像metrics 那樣基於某一個值去計算,每一個Bucket (桶)是按照我們定義的準則去判斷資料是否會落入桶(bucket)中。一個單獨的響應中,bucket(桶)的最大個數預設是10000,我們可以通過serarch.max_buckets
去進行調整。
如果從定義來看,理解Bucket聚合查詢還是比較難的,而且Bucket聚合查詢的種類也有很多,給大家一一介紹不太可能,我們舉兩個實際中用的比較多的例子吧。在上面的metrics 聚合中,我們可以查詢到數量(count),但是我們能不能分組呢?是不是和資料庫中的group by
聯絡起來了?對,Bucket 聚合查詢就像是資料庫中的group by
,我們還用上面銀行的索引,比如說我們要看各個年齡段的存款人數,那麼查詢語句我們該怎麼寫呢?這裡就要使用Bucket 聚合中的Terms聚合查詢,查詢語句如下:
POST /bank/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
}
}
},
"aggs": {
"ages": {
"terms": {
"field": "age"
}
}
}
}
其中,ages
是我們定義的聚合查詢的名稱,terms
指定要分組的列,我們執行一下,看看結果,
……
{
"aggregations": {
"ages": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 463,
"buckets": [
{
"key": 31,
"doc_count": 61
}
,
{
"key": 39,
"doc_count": 60
}
,
{
"key": 26,
"doc_count": 59
}
,
{
"key": 32,
"doc_count": 52
}
,
{
"key": 35,
"doc_count": 52
}
,
{
"key": 36,
"doc_count": 52
}
,
{
"key": 22,
"doc_count": 51
}
,
{
"key": 28,
"doc_count": 51
}
,
{
"key": 33,
"doc_count": 50
}
,
{
"key": 34,
"doc_count": 49
}
]
}
}
我們可以看到在返回的結果中,每個年齡的資料都彙總出來了。假如我們要看每個年齡段的存款餘額,該怎麼辦呢?這裡就要用到子聚合查詢了,在Bucket 聚合中,再加入子聚合查詢了,我們看看怎麼寫,
POST /bank/_search
{
"query": {
"bool": {
"must": {
"match_all": {}
}
}
},
"aggs": {
"ages": {
"terms": {
"field": "age"
},
"aggs": {
"sum_balance": {
"sum": {
"field": "balance"
}
}
}
}
}
}
我們在聚合型別terms
的後面又加了子聚合查詢,在子聚合查詢中,又自定義了一個sum_balance
的查詢,它是一個metrics
聚合查詢,要對欄位balance
進行求和。我們執行一下,看看結果。
"aggregations": {
"ages": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 463,
"buckets": [
{
"key": 31,
"doc_count": 61,
"sum_balance": {
"value": 1727088
}
}
,
{
"key": 39,
"doc_count": 60,
"sum_balance": {
"value": 1516175
}
}
,
{
"key": 26,
"doc_count": 59,
"sum_balance": {
"value": 1368494
}
}
,
{
"key": 32,
"doc_count": 52,
"sum_balance": {
"value": 1245470
}
}
,
{
"key": 35,
"doc_count": 52,
"sum_balance": {
"value": 1151108
}
}
,
{
"key": 36,
"doc_count": 52,
"sum_balance": {
"value": 1153085
}
}
,
{
"key": 22,
"doc_count": 51,
"sum_balance": {
"value": 1261285
}
}
,
{
"key": 28,
"doc_count": 51,
"sum_balance": {
"value": 1441968
}
}
,
{
"key": 33,
"doc_count": 50,
"sum_balance": {
"value": 1254697
}
}
,
{
"key": 34,
"doc_count": 49,
"sum_balance": {
"value": 1313688
}
}
]
}
}
我們看到返回結果中,增加了我們定義的sum_balance
欄位,它是balance
餘額的彙總。這個例子我們應該對bucket(桶)這個概念有了一個非常形象的認識了。還有一些其他的bucket聚合查詢,這裡就不給大家一一介紹了,比如:我們只想查某幾個年齡段的餘額彙總,就可以使用filters-aggregation
。
好了,ES的一些基本的聚合查詢就給大家介紹到這裡了,如果要用到一些其他的聚合查詢,可以參照ES的官方文件。