原文鏈接:es筆記七之聚合操作之桶聚合和矩陣聚合
桶(bucket)聚合并不像指標(biāo)(metric)聚合一樣在字段上計(jì)算谤辜,而是會(huì)創(chuàng)建數(shù)據(jù)的桶丑念,我們可以理解為分組,根據(jù)某個(gè)字段進(jìn)行分組渔彰,將符合條件的數(shù)據(jù)分到同一個(gè)組里恍涂。
桶聚合可以有子聚合乳丰,意思就是在分組之后内贮,可以在每個(gè)組里再次進(jìn)行聚合操作什燕,聚合的數(shù)據(jù)就是每個(gè)組的數(shù)據(jù)竞端。
以下是本篇筆記目錄:
- 基本桶聚合操作
- 過(guò)濾聚合
- 多桶過(guò)濾聚合
- 全局聚合
- 直方圖聚合
- 嵌套聚合
- 范圍聚合
- 稀有詞聚合
- 矩陣聚合
1技俐、基本桶聚合操作
我們可以簡(jiǎn)單的先來(lái)進(jìn)行一下桶聚合的操作雕擂,比如我們根據(jù) age 字段對(duì)數(shù)據(jù)進(jìn)行分組操作:
GET /bank/_search
{
"size": 0,
"aggs": {
"bucket_age": {
"terms": {
"field": "age",
"size": 20
}
}
}
}
返回的數(shù)據(jù)如下:
{
...
"aggregations" : {
"bucket_age" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 35,
"buckets" : [
{
"key" : 31,
"doc_count" : 61
},
{
"key" : 39,
"doc_count" : 60
},
{
"key" : 26,
"doc_count" : 59
},
...
]
}
}
}
所有的數(shù)據(jù)在 aggregations.bucket_age.buckets 下井赌,這是一個(gè)數(shù)組仇穗,key 的內(nèi)容為 age 的值纹坐,doc_count 為該 age 值的數(shù)據(jù)條數(shù)恰画。
其中拴还,bucket_age 為我們定義的桶聚合的名稱片林。
接下來(lái)我們介紹桶聚合和指標(biāo)聚合的其他操作费封。
2弓摘、過(guò)濾聚合
如果我們想針對(duì)某特定的數(shù)據(jù)進(jìn)行聚合韧献,那么就涉及數(shù)據(jù)的過(guò)濾锤窑,篩選出特定的數(shù)據(jù)進(jìn)行聚合探橱。
比如我們想篩選出 gender 的值為 "F" 的數(shù)據(jù)绘证,然后對(duì)其進(jìn)行取平均數(shù)的操作胞枕,我們可以使用 filter 來(lái)如下操作:
GET /bank/_search
{
"size": 0,
"aggs": {
"bucket_gender": {
"filter": {"term": {"gender.keyword": "F"}},
"aggs": {
"avg_balance": {"avg": {"field": "balance"}}
}
}
}
}
aggs.bucket_gender 我們使用 filter 對(duì)數(shù)據(jù)進(jìn)行了一個(gè)過(guò)濾曲稼,篩選出 gender 的值為 "F" 的數(shù)據(jù)贫悄。
注意窄坦,在這里凳寺,因?yàn)槲覀儗?xiě)入數(shù)據(jù)前肠缨,沒(méi)有預(yù)先定義字段的類型闻书,所以 es 中將其自動(dòng)轉(zhuǎn)化成 text 屬性的字段魄眉,所以在查詢的時(shí)候用到的是 gender.keyword坑律,意思是對(duì) gender 字段的內(nèi)容作為整體進(jìn)行篩選晃择。
如果本身是 keyword 屬性藕各,就不用加 .keyword 來(lái)操作激况。
與 filter 同級(jí)的 aggs乌逐,進(jìn)行針對(duì)篩選出的數(shù)據(jù)進(jìn)行聚合的操作,這里我們用到的是平均值洛波。
返回的數(shù)據(jù)如下:
...
"aggregations" : {
"bucket_gender" : {
"doc_count" : 493,
"avg_balance" : {
"value" : 25623.34685598377
}
}
}
}
3蹬挤、多桶過(guò)濾聚合
在上一點(diǎn)我們過(guò)濾的是單個(gè)條件焰扳,gender='F' 的情況吨悍,如果我們想要實(shí)現(xiàn)多個(gè)過(guò)濾來(lái)操作葫隙,可以使用 filters躏仇,使用方法也不一樣慧起。
比如我們想分別對(duì) gender 的值為 F 和 M 的數(shù)據(jù)進(jìn)行均值操作蚓挤,我們可以一步步來(lái)操作灿意,我們先來(lái)通過(guò) filters 實(shí)現(xiàn)兩個(gè)桶的聚合:
GET /bank/_search
{
"size": 0,
"aggs": {
"bucket_gender": {
"filters": {
"filters": {
"female": {"term": {"gender.keyword": "F"}},
"male": {"term": {"gender.keyword": "M"}}
}
}
}
}
}
返回的數(shù)據(jù)就是兩個(gè)桶缤剧,包含了兩類數(shù)據(jù)的總數(shù):
...
"aggregations" : {
"bucket_gender" : {
"buckets" : {
"female" : {
"doc_count" : 493
},
"male" : {
"doc_count" : 507
}
}
}
}
}
如果想在此基礎(chǔ)上接著對(duì)其進(jìn)行均值計(jì)算荒辕,和前面的 filter 操作一樣,在第一個(gè) filters 同級(jí)的地方李皇,加上我們的指標(biāo)聚合操作:
GET /bank/_search
{
"size": 0,
"aggs": {
"bucket_gender": {
"filters": {
"filters": {
"female": {"term": {"gender.keyword": "F"}},
"male": {"term": {"gender.keyword": "M"}}
}
},
"aggs": {
"avg_balance": {"avg": {"field": "balance"}}
}
}
}
}
這樣茧跋,在返回的桶的數(shù)據(jù)之內(nèi)厌衔,還包含了一個(gè)均值的結(jié)果:
...
"aggregations" : {
"bucket_gender" : {
"buckets" : {
"female" : {
"doc_count" : 493,
"avg_balance" : {
"value" : 25623.34685598377
}
},
"male" : {
"doc_count" : 507,
"avg_balance" : {
"value" : 25803.800788954635
}
}
}
}
}
}
這里我們因?yàn)?gender 只有 F 和 M 兩個(gè)值,所以沒(méi)有第三類數(shù)據(jù)捍岳,對(duì)于其他數(shù)據(jù),比如 age睬隶,有很多值锣夹,除了某幾種特定的值外,我們還想獲取剩下的值的信息苏潜,如何操作呢银萍?
這里使用到 other_bucket_key 這個(gè)參數(shù),比如我們除了定義的 female 和 male恤左,我們還定義一個(gè) non_gender 字段來(lái)統(tǒng)計(jì)非 M 和 F 的值,我們可以這樣操作:
GET /bank/_search
{
"size": 0,
"aggs": {
"bucket_gender": {
"filters": {
"other_bucket_key": "non_gender",
"filters": {
"female": {"term": {"gender.keyword": "F"}},
"male": {"term": {"gender.keyword": "M"}}
}
}
}
}
}
返回的值如下:
...
"aggregations" : {
"bucket_gender" : {
"buckets" : {
"female" : {
"doc_count" : 493,
"avg_balance" : {
"value" : 25623.34685598377
}
},
"male" : {
"doc_count" : 507,
"avg_balance" : {
"value" : 25803.800788954635
}
},
"non_gender" : {
"doc_count" : 0,
"avg_balance" : {
"value" : null
}
}
}
}
}
}
4瓶您、全局聚合
如果我們要在限定的范圍內(nèi)進(jìn)行聚合郑叠,但是又想在全局范圍內(nèi)獲取聚合數(shù)據(jù)進(jìn)行比對(duì)沸版。
比如說(shuō),我們?cè)?gender='F' 的范圍進(jìn)行聚合操作:
GET /bank/_search
{
"size": 0,
"query": {"match": {"gender.keyword": "F"}},
"aggs": {
"female_balance_avg": {
"avg": {
"field": "balance"
}
}
}
}
這里通過(guò) query 操作篩選 gender='F' 的數(shù)據(jù),然后對(duì) balance 字段進(jìn)行聚合,如果同時(shí)我們想要獲取所有數(shù)據(jù)的 balance 的平均值,我們可以使用 global 來(lái)操作,如下:
GET /bank/_search
{
"size": 0,
"query": {"match": {"gender.keyword": "F"}},
"aggs": {
"total_balance_avg": {
"global": {},
"aggs": {
"avg_balance": {
"avg": {"field": "balance"}
}
}
},
"female_balance_avg": {
"avg": {
"field": "balance"
}
}
}
}
這樣就有兩個(gè)數(shù)據(jù)來(lái)比對(duì)恢着,結(jié)果如下:
...
"aggregations" : {
"female_balance_avg" : {
"value" : 25623.34685598377
},
"total_balance_avg" : {
"doc_count" : 1000,
"avg_balance" : {
"value" : 25714.837
}
}
}
}
5碗淌、直方圖聚合
這是個(gè)類似于直方圖的區(qū)間桶的聚合操作纳像。
比如對(duì)于 age 字段岔帽,我們想以 5 為步長(zhǎng)進(jìn)行聚合,如果 age 字段在 20-50 之間,那么返回的數(shù)據(jù)就會(huì)類似于 20-24导犹,25-29舶得,30-34... 以及落在這些區(qū)間的數(shù)據(jù)的數(shù)量。
而返回的每條數(shù)據(jù)并不會(huì)是一個(gè)區(qū)間梅惯,而是一個(gè)開(kāi)始的數(shù)據(jù)葫哗,也就是說(shuō)上面的例子會(huì)返回的 key 是 20鸟廓,25煌张,30 等怀泊。
比如我們想對(duì) age 字段進(jìn)行直方圖聚合,步長(zhǎng)為 5,用到的聚合的字段為 histogram榨咐,示例如下:
GET /bank/_search
{
"size": 0,
"aggs": {
"age_histogram": {
"histogram": {
"field": "age",
"interval": 5
}
}
}
}
在 histogram 聚合字段下,field 字段為我們要進(jìn)行直方圖聚合的字段,這里是 age 字段包竹,interval 字段為進(jìn)行劃分的區(qū)間退盯,我們定義為 5漓骚。
返回的數(shù)據(jù)如下:
...
"aggregations" : {
"age_histogram" : {
"buckets" : [
{
"key" : 20.0,
"doc_count" : 225
},
{
"key" : 25.0,
"doc_count" : 226
}
...
]
}
}
注意: 如果我們進(jìn)行聚合的區(qū)間,比如說(shuō) 25-29 之間聚合的數(shù)據(jù)是 0淆九,那么 es 還是會(huì)返回這個(gè)區(qū)間嘲驾,不過(guò) doc_count 是 0,不會(huì)存在不返回這個(gè)區(qū)間 key 的情況帖池。
最小 count 返回?cái)?shù)據(jù)
前面我們說(shuō)了就算區(qū)間 count 數(shù)是0村怪,這個(gè)區(qū)間也會(huì)返回懂昂,但同時(shí)我們也可以規(guī)定 min_doc_count 這個(gè)參數(shù)來(lái)返回只有當(dāng)區(qū)間 count 數(shù)大于等于這個(gè)值的時(shí)候才返回?cái)?shù)據(jù)工三。
假設(shè) age 的區(qū)間數(shù)據(jù)如下:
20-24:5
25-29:0
30-34:2
...
如果我們?cè)O(shè)置 min_doc_count=2姥闪,那么返回的區(qū)間 25-29則不會(huì)被返回哺窄,使用示例如下:
GET /bank/_search
{
"size": 0,
"aggs": {
"age_histogram": {
"histogram": {
"field": "age",
"interval": 5,
"min_doc_count": 2
}
}
}
}
返回?cái)?shù)據(jù):
...
"aggregations" : {
"age_histogram" : {
"buckets" : [
{
"key" : 20.0,
"doc_count" : 5
},
{
"key" : 30.0,
"doc_count" : 2
},
...
]
}
}
指定返回區(qū)間
前面介紹的示例中,如果數(shù)據(jù)在 20-50 之間衙四,那么返回的區(qū)間數(shù)據(jù)就從 20 開(kāi)始計(jì)數(shù)(具體的 key 會(huì)根據(jù) interval 的設(shè)置不一樣,比如設(shè)置 Interval=5,key 就會(huì)是 20, 25, 30...显歧,如果是設(shè)置 Interval=3,那么 key 就會(huì)是 18, 21, 24...)。
如果我們想從 0 開(kāi)始計(jì)數(shù)沪停,即便是 0-20 之間的計(jì)數(shù)為 0蛛株,也想要返回20之前 0-4,5-9 的數(shù)育拨,或者想要返回 50 之后的數(shù)據(jù)谨履,包括 50-54,55-59 這種熬丧,我們可以使用extended_bounds.min 和 extended_bounds.max 來(lái)限定返回?cái)?shù)據(jù)的最大最小值笋粟,示例如下:
GET /bank/_search
{
"size": 0,
"aggs": {
"age_histogram": {
"histogram": {
"field": "age",
"interval": 5,
"extended_bounds": {
"min": 0,
"max": 90
}
}
}
}
}
這樣返回的數(shù)據(jù)的區(qū)間就會(huì)在 0-90 之間,即便在全量數(shù)據(jù)的范圍之外析蝴。
注意: 因?yàn)樵跀?shù)據(jù)區(qū)間之外的數(shù)據(jù)為 0害捕,想要擴(kuò)展的區(qū)間返回顯示,記得要將最小返回計(jì)數(shù)值 min_doc_count 置為 0闷畸。
6尝盼、嵌套聚合
嵌套聚合,這里針對(duì)的是 es 中數(shù)據(jù)字段為數(shù)組佑菩,數(shù)組元素里又嵌套為對(duì)象的情況盾沫,官方文檔舉了個(gè)例子,新建一個(gè) products 的 index倘待,數(shù)據(jù)結(jié)構(gòu)如下:
PUT /products
{
"mappings": {
"properties" : {
"resellers" : {
"type" : "nested",
"properties" : {
"reseller" : { "type" : "text" },
"price" : { "type" : "double" }
}
}
}
}
}
接下來(lái)我們往里添加兩條條數(shù)據(jù):
PUT /products/_doc/0
{
"name": "LED TV",
"resellers": [
{
"reseller": "companyA",
"price": 350
},
{
"reseller": "companyB",
"price": 500
}
]
}
PUT /products/_doc/1
{
"name": "LED TV",
"resellers": [
{
"reseller": "companyA",
"price": 400
},
{
"reseller": "companyB",
"price": 250
}
]
}
然后我們想要在這兩條數(shù)據(jù)里的 resellers 數(shù)組字段里的四個(gè)元素里獲取 price 字段最小值疮跑,可以通過(guò) nested.path 來(lái)指定 resellers 字段组贺,然后進(jìn)行聚合凸舵,使用示例如下:
GET /products/_search
{
"size": 0,
"query" : {
"match" : { "name" : "led tv" }
},
"aggs" : {
"resellers" : {
"nested" : {
"path" : "resellers"
},
"aggs" : {
"min_price" : { "min" : { "field" : "resellers.price" } }
}
}
}
}
7、范圍聚合
范圍聚合失尖,即 range 聚合啊奄。我們可以通過(guò)指定范圍來(lái)返回各個(gè)桶的數(shù)據(jù)渐苏,這個(gè)操作和直方圖聚合是類似的,不過(guò)這個(gè)操作更靈活菇夸,聚合的范圍不會(huì)寫(xiě)死琼富。
如果是希望步長(zhǎng)固定,我們可以使用直方圖聚合庄新,比如0-4鞠眉,5-9 這種,如果我們直接想要自定義的 0-7择诈,8-19 這種我們想要定義的可以使用范圍聚合械蹋。
還是使用 age 字段來(lái)操作,比如我們想要獲取 小于27羞芍,28-35哗戈,大于36 這個(gè)范圍,我們可以如下操作:
GET /bank/_search
{
"size": 0,
"aggs": {
"age_range": {
"range": {
"field": "age",
"ranges": [
{"to": 27},
{"from": 27, "to": 35},
{"from": 35}
]
}
}
}
}
需要注意的是荷科,from 的參數(shù)是開(kāi)區(qū)間的唯咬,比如我們這里 from=27,那么邏輯就是 >27畏浆,如果區(qū)間兩邊沒(méi)有限制胆胰,不填寫(xiě)相應(yīng)的 from 和 to 參數(shù)即可,返回的 key 也會(huì)是 *-27 這種形式刻获。
上面的命令返回的數(shù)據(jù)如下:r
...
"aggregations" : {
"age_range" : {
"buckets" : [
{
"key" : "*-27.0",
"to" : 27.0,
"doc_count" : 326
},
{
"key" : "27.0-35.0",
"from" : 27.0,
"to" : 35.0,
"doc_count" : 384
},
{
"key" : "35.0-*",
"from" : 35.0,
"doc_count" : 290
}
]
}
}
}
如果想要返回的數(shù)據(jù)以 key:{} 的形式返回煮剧,可以加上 keyed=true 參數(shù):
GET /bank/_search
{
"size": 0,
"aggs": {
"age_range": {
"range": {
"field": "age",
"keyed": true,
"ranges": [
{"to": 27},
{"from": 27, "to": 35},
{"from": 35}
]
}
}
}
}
桶的子指標(biāo)聚合
在上面的桶聚合操作之后,我們還可以對(duì)每個(gè)桶進(jìn)行子指標(biāo)聚合将鸵,比如說(shuō)最大最小值勉盅,平均值,或者統(tǒng)計(jì)值等顶掉,以下是個(gè)操作示例:
GET /bank/_search
{
"size": 0,
"aggs": {
"age_range": {
"range": {
"field": "age",
"ranges": [
{"to": 27},
{"from": 27, "to": 35},
{"from": 35}
]
},
"aggs": {
"age_stats": {
"stats": {
"field": "age"
}
}
}
}
}
}
進(jìn)行指標(biāo)聚合的范圍是分到每個(gè)桶的數(shù)據(jù)草娜。
8、稀有詞聚合
rare terms aggregation痒筒,這個(gè)的概念大概是這樣的宰闰,比如我們根據(jù) age 字段進(jìn)行聚合,統(tǒng)計(jì)他們?cè)谖臋n中出現(xiàn)的次數(shù)簿透,我們想要獲取出現(xiàn)次數(shù)最少的幾個(gè)移袍,或者指定出現(xiàn)次數(shù)少于 50 的 age 值,就可以用到這個(gè)操作老充。
接下來(lái)我們對(duì) age 字段進(jìn)行這樣的操作葡盗,只獲取出現(xiàn)次數(shù)少于 50 的數(shù)據(jù),示例如下:
GET /bank/_search
{
"size": 0,
"aggs": {
"rare_age": {
"rare_terms": {
"field": "age",
"max_doc_count": 50
}
}
}
}
這個(gè)的關(guān)鍵字是 rare_terms啡浊,rare_age 是我們指定的聚合名稱觅够,其下 field 是我們進(jìn)行聚合字段胶背,在這里是 age 字段,max_doc_count 則是我們指定的出現(xiàn)次數(shù)最大的值喘先。
返回的數(shù)據(jù)會(huì)按照 doc_count 正序排列返回钳吟,大致如下:
...
"aggregations" : {
"rare_age" : {
"buckets" : [
{
"key" : 29,
"doc_count" : 35
},
{
"key" : 27,
"doc_count" : 39
},
{
"key" : 38,
"doc_count" : 39
},
...
范圍過(guò)濾
我們還可以使用過(guò)濾的方式來(lái)指定或者排除某些值,這個(gè)操作是支持正則的窘拯,但經(jīng)過(guò)測(cè)試红且,發(fā)現(xiàn)按照官方文檔使用正則的 * 來(lái)篩選數(shù)據(jù)并不能真正起作用,所以這里我們介紹使用列表來(lái)實(shí)現(xiàn)過(guò)濾涤姊。
比如我們指定的 age 范圍是 [29, 27, 24]直焙,使用 include:
GET /bank/_search
{
"size": 0,
"aggs": {
"rare_age": {
"rare_terms": {
"field": "age",
"max_doc_count": 51,
"include": [29, 27, 24]
}
}
}
}
如果我們要排除的 age 范圍是 [29, 27, 24],使用 exclude:
GET /bank/_search
{
"size": 0,
"aggs": {
"rare_age": {
"rare_terms": {
"field": "age",
"max_doc_count": 51,
"exclude": [29, 27, 24]
}
}
}
}
9砂轻、矩陣聚合
矩陣聚合是很小的一部分奔誓,這里直接介紹一下。
前面在指標(biāo)聚合的介紹中搔涝,有一個(gè)聚合統(tǒng)計(jì)匯總厨喂,其中介紹了一個(gè)參數(shù)是 stats,會(huì)返回對(duì)應(yīng)字段的最大值庄呈、最小值蜕煌、總數(shù)等數(shù)據(jù),矩陣聚合 matrix 可以理解成是多個(gè)字段的 stats 的集合诬留,會(huì)缺少一些統(tǒng)計(jì)值斜纪,但是返回的值更偏統(tǒng)計(jì)學(xué)方面的用途。
使用示例如下:
GET /bank/_search
{
"size": 0,
"aggs": {
"field_statis": {
"matrix_stats": {
"fields": ["age", "balance"]
}
}
}
}
返回的數(shù)據(jù)如下:
...
"aggregations" : {
"field_statis" : {
"doc_count" : 1000,
"fields" : [
{
"name" : "balance",
"count" : 1000,
"mean" : 25714.837000000014,
"variance" : 1.9757153733576667E8,
"skewness" : -0.009992486755643138,
"kurtosis" : 1.8088323899074914,
"covariance" : {
"balance" : 1.9757153733576667E8,
"age" : -2845.650777777781
},
"correlation" : {
"balance" : 1.0,
"age" : -0.033676422195874786
}
},
{
"name" : "age",
"count" : 1000,
...
}
...
其中文兑,各參數(shù)的釋義如下:
count: 總數(shù)
mean: 平均值
variance: 方差
skewness: 偏度
kurtosis: 峰度
covariance: 協(xié)方差
correlation: 與其他字段的相關(guān)性盒刚,比如 age 到 age 字段的相關(guān)性就是 1.0