編程隨筆-ElasticSearch知識導(dǎo)圖(5):聚合

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)

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
  2. 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):管理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末葛峻,一起剝皮案震驚了整個濱河市锹雏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌术奖,老刑警劉巖礁遵,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異采记,居然都是意外死亡佣耐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門唧龄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兼砖,“玉大人,你說我怎么就攤上這事既棺》硇” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵丸冕,是天一觀的道長耽梅。 經(jīng)常有香客問我,道長胖烛,這世上最難降的妖魔是什么眼姐? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮佩番,結(jié)果婚禮上众旗,老公的妹妹穿的比我還像新娘。我一直安慰自己趟畏,他們只是感情好逝钥,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般艘款。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沃琅,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天哗咆,我揣著相機與錄音,去河邊找鬼益眉。 笑死晌柬,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的郭脂。 我是一名探鬼主播年碘,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼展鸡!你這毒婦竟也來了屿衅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤莹弊,失蹤者是張志新(化名)和其女友劉穎涤久,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忍弛,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡响迂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了细疚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔗彤。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疯兼,靈堂內(nèi)的尸體忽然破棺而出然遏,到底是詐尸還是另有隱情,我是刑警寧澤镇防,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布啦鸣,位于F島的核電站,受9級特大地震影響来氧,放射性物質(zhì)發(fā)生泄漏诫给。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一啦扬、第九天 我趴在偏房一處隱蔽的房頂上張望中狂。 院中可真熱鬧,春花似錦扑毡、人聲如沸胃榕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勋又。三九已至苦掘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間楔壤,已是汗流浹背鹤啡。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蹲嚣,地道東北人递瑰。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像隙畜,于是被迫代替她去往敵國和親抖部。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容