1. 聚合模式
??聚合(Aggregations)是對數(shù)據(jù)庫中數(shù)據(jù)域進行統(tǒng)計分析的手段,關(guān)系數(shù)據(jù)庫中我們常會用到avg,sum,count茂嗓,group by這些聚合手段進行簡單的統(tǒng)計與分析钥勋。在ES中也提供了同樣的功能炬转,根據(jù)使用模式,分為以下幾種:
- 數(shù)字指標(biāo)(metrics)聚合:根據(jù)輸出的是單值的還是多值的分為單值數(shù)字指標(biāo)與多值數(shù)字指標(biāo)算灸,計算使用的域可直接從文本中抽取也可使用腳本生成扼劈。
- 分組(bucket)聚合:分組聚合創(chuàng)建文檔對象的分組。每個分組都與一個分組依據(jù) (憑證)相關(guān)聯(lián)(取決于聚合類型)菲驴,該依據(jù)確定當(dāng)前上下文中的文檔是否“屬于”其中荐吵。分組聚合還計算并返回每個分組中文檔數(shù)量。分組聚合可以嵌套赊瞬,即一個分組中還可以定義子分組先煎。分組聚合支持對父子關(guān)系對象和嵌套對象的聚合。
- 管道(Pipeline)聚合:處理來自其它聚合的數(shù)據(jù)巧涧,而不是直接計算文檔對象的域值得到輸出薯蝎。管道聚合可以分為兩類:
- 父(parent)聚合:一組管道聚合的輸入數(shù)據(jù)由其父聚合的輸出提供,能夠計算新分組或新聚合添加到現(xiàn)有組中谤绳。
- 兄弟(sibling)聚合:輸入數(shù)據(jù)由同級聚合的輸出提供占锯,新產(chǎn)生的聚合域與所使用的輸入聚合同級袒哥。
??文獻(xiàn)1中還提到了矩陣(Matrix)聚合,它對多個字段進行操作烟央,并根據(jù)字段值生成一個矩陣結(jié)果统诺,該矩陣是對這些字段的一些統(tǒng)計數(shù)據(jù)。因為比較小眾疑俭,本文中不做討論粮呢。
??數(shù)字指標(biāo)聚合、分組聚合類似于關(guān)系數(shù)據(jù)庫中的avg,sum,count钞艇,group by等聚合形式啄寡,在應(yīng)用系統(tǒng)中經(jīng)常會使用。管道聚合是數(shù)字指標(biāo)聚合及分組聚合的進階使用哩照,語法派生于數(shù)字指標(biāo)聚合挺物、分組聚合,本文暫不探討飘弧,有興趣的同學(xué)看參考文獻(xiàn)1识藤。
??可將數(shù)字指標(biāo)聚合、分組聚合的語法和用法總結(jié)如下一張導(dǎo)圖次伶。
2. 與查詢指令結(jié)合
??聚合指令使用檢索DSL(search DSL)定義痴昧,因而也使用檢索指令的URI(標(biāo)識為“_search”),請求消息體中若包含以“query”指示的查詢指令冠王,則以“aggs”指示的聚合指令進行聚合操作的對象為“query”指令的查詢結(jié)果赶撰;若不包含“query”指令,則表示進行聚合操作的對象為索引中所有對象柱彻。
??仍以《編程隨筆-ElasticSearch知識導(dǎo)圖(3):映射》中第2節(jié)中的銀行賬號索引為例豪娜,考察下面一個簡單聚合指令,計算銀行余額的均值:
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size":0,
"aggs": {
"avg_balance": {
"avg": {
"field": "balance"
}
}
}
}
'
??該命令計算bank索引中所有賬戶的余額平均值哟楷,若想查詢年齡在30到40之間客戶的記錄和平均余額瘤载,則可使用下面的指令。
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"query": {
"range": {
"age": {
"lte": 40,
"gte": 30
}
}
},
"aggs": {
"avg_balance": {
"avg": {
"field": "balance"
}
}
}
}
'
??若只是想了解年齡在30到40之間客戶的平均余額卖擅,則可使用如下聚合指令(注意范圍分組中不包含“to”的值):
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size":0,
"aggs": {
"avg_balance_by_age": {
"range": {
"field": "age",
"ranges": [
{
"to": 41,
"from": 30
}
]
},
"aggs": {
"avg_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
'
3. 常用模式設(shè)計
3.1. 聚合模式表示
??以我們熟悉的SQL語言作為范式惕虑,我們將應(yīng)用中的常用聚合查詢使用SQL表示為如下模式:
SELECT [$field_1] FROM $index_name WHERE $filter_clause GROUP BY [$field_2] ORDER BY [$field_3]
??其中:
- [$field_1]是在返回結(jié)果顯示的字段名集合,$field_1有可能是實施聚合操作的聚合值,也可以是分組[$field_2]中的字段磨镶。
- $index_name是索引名。
- [$field_2]是分組依據(jù)的字段健提,可能為多個字段琳猫。
- [$field_3]是排序字段,可能為多個字段私痹。
- $filter_clause是過濾條件脐嫂。
3.2. 多分組字段
??對于聚合中的多個分組字段统刮,在聚合指令中可以使用兩種格式:一種使用 基于“terms”子句的嵌套分組方式,另一種使用基于“composite”子句的多字段分組方式账千。
??本文建議如果有只有一個分組字段侥蒙,使用”terms”定義分組,如果包含多個分組字段匀奏,則使用“composite”定義多個分組字段鞭衩。
??考慮如下聚合查詢用例,按賬戶所在的州與性別分組娃善,獲取每組的余額最大值:
SELECT state,gender,max(balance) FROM bank GROUP BY state,gender
??使用基于“composite”子句的分組方式聚合指令如下所示:
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"group_by_state_gender": {
"composite": {
"sources": [
{
"state": {
"terms": {
"field": "state.keyword"
}
}
},
{
"gender": {
"terms": {
"field": "gender.keyword"
}
}
}
]
},
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
}
}
}
}
'
??返回結(jié)果(部分)顯示如下:
"aggregations" : {
"group_by_state_gender" : {
"after_key" : {
"state" : "AK",
"gender" : "F"
},
"buckets" : [
{
"key" : {
"state" : "AK",
"gender" : "F"
},
"doc_count" : 10,
"max_balance" : {
"value" : 44043.0
}
}
]
}
}
??使用基于“terms”子句的嵌套分組方式聚合指令如下所示:
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"group_by_gender": {
"terms": {
"field": "gender.keyword"
},
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
}
}
}
}
}
}
'
??返回結(jié)果(部分)顯示如下所示:
"aggregations" : {
"group_by_state" : {
"doc_count_error_upper_bound" : 28,
"sum_other_doc_count" : 978,
"buckets" : [
{
"key" : "TX",
"doc_count" : 22,
"group_by_gender" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "F",
"doc_count" : 13,
"max_balance" : {
"value" : 49587.0
}
},
{
"key" : "M",
"doc_count" : 9,
"max_balance" : {
"value" : 42736.0
}
}
]
}
}
]
}
}
??從兩種查詢方式的結(jié)果格式來看论衍,使用“composite”方式的查詢指令返回結(jié)果更符合我的使用習(xí)慣。
3.3. 排序
??可對聚合查詢的結(jié)果用于拍尋聚磺,用于排序字段的可為分組字段坯台,也可為聚合操作結(jié)果。將上節(jié)的查詢要求改為如下形式:
SELECT state,gender,max(balance) FROM bank GROUP BY state,gender ORDER BY state ASC ,gender ASC
??則查詢指令可修改為如下形式:
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"group_by_state_gender": {
"composite": {
"sources": [
{
"state": {
"terms": {
"field": "state.keyword",
"order": "ASC"
}
}
},
{
"gender": {
"terms": {
"field": "gender.keyword",
"order": "ASC"
}
}
}
]
},
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
}
}
}
}
'
??需要注意的是:“composite”形式的聚合查詢只支持對分組字段的排序瘫寝,如果要使用聚合值作為排序字段蜒蕾,請使用“terms”形式用于分組的子句,如下面的示例焕阿。
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"max_balance": "DESC"
}
},
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
}
}
}
}
'
3.4. 分頁
??如果聚合查詢的返回記錄較多咪啡,ES在一次返回結(jié)果中默認(rèn)返回10條。如果需要獲取所有記錄捣鲸,則需要設(shè)置分頁參數(shù)進行多次查詢瑟匆。
??仍然考慮3.2節(jié)的查詢示例,分組結(jié)果可能有100個左右的分組栽惶,若設(shè)置每次查詢結(jié)果返回5個分組愁溜,可以設(shè)置如下查詢指令:
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"group_by_state_gender": {
"composite": {
"size": 5,
"sources": [
{
"state": {
"terms": {
"field": "state.keyword",
"order": "ASC"
}
}
},
{
"gender": {
"terms": {
"field": "gender.keyword",
"order": "ASC"
}
}
}
]
},
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
}
}
}
}
'
??對于使用了“composite”形式的查詢指令,在返回結(jié)果中包含一個“after_key”對象外厂,標(biāo)識本次查詢結(jié)果的最后一個分組標(biāo)識冕象,如果在下次查詢中攜帶該對象,ES會返回此對象所標(biāo)識分組后面的分組記錄汁蝶,查詢指令如下所示(注意指令中的“after”對象渐扮,提供了類似游標(biāo)的功能,每次根據(jù)上次查詢結(jié)果的“after_key”進行改變):
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size": 0,
"aggs": {
"group_by_state_gender": {
"composite": {
"size": 5,
"after": {
"state" : "AR",
"gender" : "F"
},
"sources": [
{
"state": {
"terms": {
"field": "state.keyword",
"order": "ASC"
}
}
},
{
"gender": {
"terms": {
"field": "gender.keyword",
"order": "ASC"
}
}
}
]
},
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
}
}
}
}
'
??對于使用 “terms”的嵌套分組方式的聚合查詢指令無法使用類似“游標(biāo)”功能掖棉,只能返回指定數(shù)目的分組結(jié)果墓律。
3.5. 過濾條件處理
??如果聚合查詢中有過濾條件,最簡單的方式是在查詢指令中增加“query”子句幔亥,參看第2節(jié)的描述耻讽。
3.6. 設(shè)計模式
??現(xiàn)在我們可以對查詢要求:
SELECT [$field_1] FROM $index_name WHERE $filter_clause GROUP BY [$field_2] ORDER BY [$field_3]
??定義一個常用的聚合查詢模式,如下所示:
{
"query": {
"$filter_clause": {}
},
"aggs": {
"group_by_field": {
"composite": {
"size": {},
"after": {},
"sources": [
"[$field_2]",
"[$field_3]"
]
},
"aggs": {
"aggregate_operation": {
"[$field_1]": {}
}
}
}
}
}
??考慮如下查詢要求:
SELECT state,gender,max(balance) FROM bank WHERE age>=40 GROUP BY state,gender ORDER BY state ASC ,gender ASC
??使用上面的設(shè)計模式帕棉,可以表示為如下指令:
curl -iXPOST 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
"size": 0,
"query": {
"range": {
"age": {
"gte": 40
}
}
},
"aggs": {
"group_by_state_gender": {
"composite": {
"size": 5,
"sources": [
{
"state": {
"terms": {
"field": "state.keyword",
"order": "ASC"
}
}
},
{
"gender": {
"terms": {
"field": "gender.keyword",
"order": "ASC"
}
}
}
]
},
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
}
}
}
}
'
4. SQL訪問支持
??最后告訴大家一個好消息针肥,ES提供SQL語言訪問饼记,基于XPACK插件實現(xiàn)。相比于復(fù)雜的檢索DSL慰枕,SQL對于習(xí)慣于關(guān)系數(shù)據(jù)庫的用戶更加親切一些具则。
??上節(jié)的查詢要求可表示為如下SQL訪問指令:
curl -iXPOST 'localhost:9200/_xpack/sql?format=txt' -H 'Content-Type: application/json' -d'
{
"query": "SELECT state,gender,max(balance) FROM bank WHERE age>=40 GROUP BY state,gender ORDER BY state ASC ,gender ASC"
}
'
??查詢結(jié)果如下所示:
HTTP/1.1 200 OK
Cursor: w6XxAgFmAWMBBGJhbmu+AQEBCWNvbXBvc2l0ZQdncm91cGJ5AQNtYXgEMTk5MQAA/wEHYmFsYW5jZQAAAP8AAP8CAAQxOTg3AQ1zdGF0ZS5rZXl3b3JkAAAB/wAAAAQxOTgzAQ5nZW5kZXIua2V5d29yZAAAAf8AAOgHAQoCBDE5ODcAAldZBDE5ODMAAU0AAgEAAAAAAQD/////DwAAAAABBXJhbmdlP4AAAAADYWdlAQAAACj/AQAAAAAAAAAAAAAAAVoDAAIAAAAAAAHZ////DwMBawQxOTg3AAABawQxOTgzAAABbQQxOTkxBXZhbHVlAAMAAAAPAAAADwAAAA8=
Took-nanos: 12179132
content-type: text/plain
content-length: 1920
state | gender | MAX(balance)
---------------+---------------+---------------
AK |F |44043.0
AK |M |37074.0
AL |M |34743.0
CA |M |25892.0
DC |F |18956.0
HI |M |2171.0
ID |F |19955.0
ID |M |16163.0
IL |M |23165.0
IN |M |11298.0
KY |F |48972.0
KY |M |47887.0
MA |F |35247.0
MI |F |13109.0
MN |F |5346.0
MO |F |49671.0
MO |M |31865.0
MS |M |29316.0
MT |F |37720.0
NC |M |34754.0
ND |F |28969.0
ND |M |46568.0
NH |F |19630.0
NH |M |2905.0
NM |F |13478.0
NM |M |44235.0
OH |F |42072.0
OK |F |28729.0
OR |M |33882.0
PA |F |49159.0
SC |M |29648.0
TX |M |6507.0
UT |F |35896.0
UT |M |43532.0
VT |F |9597.0
WA |M |18400.0
WV |F |16869.0
WY |M |32849.0
??ES提供的SQL訪問有一些限制:如結(jié)果的返回字段要么是分組字段,要么是聚合值具帮;排序字段不可為聚合值等博肋。檢索DSL語法復(fù)雜,但功能更加強大匕坯。若要快速開發(fā)束昵,ES提供的SQL訪問也不失為一種選擇。
5. 參考文獻(xiàn)
- https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
- Clinton Gormley &Zachary Tong, Elasticsearch: The Definitive Guide,2015
本系列文章:
編程隨筆-ElasticSearch知識導(dǎo)圖(1):全景
編程隨筆-ElasticSearch知識導(dǎo)圖(2):分布式架構(gòu)
編程隨筆-ElasticSearch知識導(dǎo)圖(3):映射
編程隨筆-ElasticSearch知識導(dǎo)圖(4):搜索
編程隨筆-ElasticSearch知識導(dǎo)圖(5):聚合
編程隨筆-ElasticSearch知識導(dǎo)圖(6):管理