聚合
聚合aggregations
聚合可以讓我們極其方便的實現對數據的統計、分析。例如:
-
什么品牌的手機最受歡迎?
-
這些手機的平均價格、最高價格、最低價格?
-
這些手機每月的銷售情況如何?
實現這些統計功能的比數據庫的sql要方便的多,而且查詢速度非常快,可以實現實時搜索效果。
?
基本概念
Elasticsearch中的聚合,包含多種類型,最常用的兩種,一個叫桶,一個叫度量:
桶(bucket)
桶的作用,是按照某種方式對數據進行分組,每一組數據在ES中稱為一個桶,例如我們根據國籍對人劃分,可以得到中國桶、英國桶,日本桶……或者我們按照年齡段對人進行劃分:0~10,10~20,20~30,30~40等。
Elasticsearch中提供的劃分桶的方式有很多:
-
Date Histogram Aggregation:根據日期階梯分組,例如給定階梯為周,會自動每周分為一組
-
Histogram Aggregation:根據數值階梯分組,與日期類似
-
Terms Aggregation:根據詞條內容分組,詞條內容完全匹配的為一組
-
Range Aggregation:數值和日期的范圍分組,指定開始和結束,然后按段分組
-
……
bucket aggregations 只負責對數據進行分組,并不進行計算,因此往往bucket中往往會嵌套另一種聚合:metrics aggregations即度量
?
度量(metrics)
分組完成以后,我們一般會對組中的數據進行聚合運算,例如求平均值、最大、最小、求和等,這些在ES中稱為度量
比較常用的一些度量聚合方式:
-
Avg Aggregation:求平均值
-
Max Aggregation:求最大值
-
Min Aggregation:求最小值
-
Percentiles Aggregation:求百分比
-
Stats Aggregation:同時返回avg、max、min、sum、count等
-
Sum Aggregation:求和
-
Top hits Aggregation:求前幾
-
Value Count Aggregation:求總數
-
……
為了測試聚合,我們先批量導入一些數據
創建索引:
PUT /cars {"settings": {"number_of_shards": 1,"number_of_replicas": 0},"mappings": {"transactions": {"properties": {"color": {"type": "keyword"},"make": {"type": "keyword"}}}} }注意:在ES中,需要進行聚合、排序、過濾的字段其處理方式比較特殊,因此不能被分詞。這里我們將color和make這兩個文字類型的字段設置為keyword類型,這個類型不會被分詞,將來就可以參與聚合
?
導入數據
POST /cars/transactions/_bulk { "index": {}} { "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" } { "index": {}} { "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" } { "index": {}} { "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" } { "index": {}} { "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" } { "index": {}} { "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" } { "index": {}} { "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" } { "index": {}} { "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" } { "index": {}} { "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }聚合為桶
首先,我們按照 汽車的顏色color來劃分桶
GET /cars/_search {"size" : 0,"aggs" : { "popular_colors" : { "terms" : { "field" : "color"}}} }-
size: 查詢條數,這里設置為0,因為我們不關心搜索到的數據,只關心聚合結果,提高效率
-
aggs:聲明這是一個聚合查詢,是aggregations的縮寫
-
popular_colors:給這次聚合起一個名字,任意。
-
terms:劃分桶的方式,這里是根據詞條劃分
-
field:劃分桶的字段
-
-
-
結果:
{"took": 1,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped": 0,"failed": 0},"hits": {"total": 8,"max_score": 0,"hits": []},"aggregations": {"popular_colors": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 0,"buckets": [{"key": "red","doc_count": 4},{"key": "blue","doc_count": 2},{"key": "green","doc_count": 2}]}} }-
hits:查詢結果為空,因為我們設置了size為0
-
aggregations:聚合的結果
-
popular_colors:我們定義的聚合名稱
-
buckets:查找到的桶,每個不同的color字段值都會形成一個桶
-
key:這個桶對應的color字段的值
-
doc_count:這個桶中的文檔數量
-
通過聚合的結果我們發現,目前紅色的小車比較暢銷!
桶內度量
前面的例子告訴我們每個桶里面的文檔數量,這很有用。 但通常,我們的應用需要提供更復雜的文檔度量。 例如,每種顏色汽車的平均價格是多少?
因此,我們需要告訴Elasticsearch使用哪個字段,使用何種度量方式進行運算,這些信息要嵌套在桶內,度量的運算會基于桶內的文檔進行
現在,我們為剛剛的聚合結果添加 求價格平均值的度量:
GET /cars/_search {"size" : 0,"aggs" : { "popular_colors" : { "terms" : { "field" : "color"},"aggs":{"avg_price": { "avg": {"field": "price" }}}}} }-
aggs:我們在上一個aggs(popular_colors)中添加新的aggs。可見度量也是一個聚合
-
avg_price:聚合的名稱
-
avg:度量的類型,這里是求平均值
-
field:度量運算的字段
結果:
..."aggregations": {"popular_colors": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 0,"buckets": [{"key": "red","doc_count": 4,"avg_price": {"value": 32500}},{"key": "blue","doc_count": 2,"avg_price": {"value": 20000}},{"key": "green","doc_count": 2,"avg_price": {"value": 21000}}]}} ...可以看到每個桶中都有自己的avg_price字段,這是度量聚合的結果
?
桶內嵌套桶
剛剛的案例中,我們在桶內嵌套度量運算。事實上桶不僅可以嵌套運算, 還可以再嵌套其它桶。也就是說在每個分組中,再分更多組。
比如:我們想統計每種顏色的汽車中,分別屬于哪個制造商,按照make字段再進行分桶
GET /cars/_search {"size" : 0,"aggs" : { "popular_colors" : { "terms" : { "field" : "color"},"aggs":{"avg_price": { "avg": {"field": "price" }},"maker":{"terms":{"field":"make"}}}}} }-
原來的color桶和avg計算我們不變
-
maker:在嵌套的aggs下新添一個桶,叫做maker
-
terms:桶的劃分類型依然是詞條
-
filed:這里根據make字段進行劃分
部分結果:
... {"aggregations": {"popular_colors": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 0,"buckets": [{"key": "red","doc_count": 4,"maker": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 0,"buckets": [{"key": "honda","doc_count": 3},{"key": "bmw","doc_count": 1}]},"avg_price": {"value": 32500}},{"key": "blue","doc_count": 2,"maker": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 0,"buckets": [{"key": "ford","doc_count": 1},{"key": "toyota","doc_count": 1}]},"avg_price": {"value": 20000}},{"key": "green","doc_count": 2,"maker": {"doc_count_error_upper_bound": 0,"sum_other_doc_count": 0,"buckets": [{"key": "ford","doc_count": 1},{"key": "toyota","doc_count": 1}]},"avg_price": {"value": 21000}}]}} } ...-
我們可以看到,新的聚合maker被嵌套在原來每一個color的桶中。
-
每個顏色下面都根據 make字段進行了分組
-
我們能讀取到的信息:
-
紅色車共有4輛
-
紅色車的平均售價是 $32,500 美元。
-
其中3輛是 Honda 本田制造,1輛是 BMW 寶馬制造。
-
總結