Elasticsearch 聚合基礎(一): 分组聚合(bucketing)
Elasticsearch 聚合搜尋: 分組
Elasticsearch 的聚合搜尋, 可以說是最常的用的功能了. 什麼是聚合搜尋呢? 就是針對搜尋出來的結果, 再去做計算. 比如可以計算最大值、平均值、最小值、總和、95%、分組、累加... 等等的計算.
這篇從基礎的分組開始帶大家了解如何做聚合搜尋, 以及他的概念.
範例: 球球分類
首先, 我們有一堆球球; 這些球球都有自己個別的元素, 包含形狀和顏色. 所謂分類就是讓有相同屬性的球球分到一類, 比如相同的形狀或是相同的顏色.
透過分類, 我們可以得到
- 這一坨球球裡面有哪些形狀?
- 每個形狀有幾顆球球?
- 每個形狀, 有幾個不同顏色的球球?
建立資料
那就先把資料建立進去吧, 還沒安裝的朋友請參考Hello World 系列 - Elasticsearch.
我們用批量上傳的方式來丟資料, 可以在這邊下載原始資料balls.json
注意最後一行要空白!
然後將他上傳: curl -H "Content-Type: Application/json" -XPOST 192.168.40.41:9200/demo/doc/_bulk --data-binary @balls.json
大家記得把 elasticsearch ip 換成自己的~
然後看一下, 25顆球都歸檔啦~
❯ curl http://192.168.40.41:9200/_cat/indices\?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open demo bBTVU1ssRjKvoIamaO7Irg 3 1 25 0 34kb 20.7kb
來分類吧: 用形狀分類
第一步, 我們先用形狀來分類. 我們預期得到以下結果:
注意圖片中每個分組寫著Buckets
, 意思就是桶
; Elasticsearch 當中的分組都適用桶裝的唷.
所以怎麼用 elasticsearch 辦到呢? 咱們接著做囉!
以詞(term)分類來作聚合搜尋
首先, 聚合的普遍結構長成這樣:
{
聚合: {
<聚合名字自取>: {
<聚合種類>: {
<聚合欄位>: ""
}
}
}
}
那麼以這次的目標來說 就是下面這樣
{
聚合: {
以形狀分類: {
詞分類: {
欄位: 形狀
}
}
}
}
實際操作
❯ curl -s -H "Content-Type: Application/json" -XPOST "http://192.168.40.41:9200/demo/_search" -d '
{
"size": 0,
"query": {
"bool": {}
},
"aggs": {
"group_by_shape": {
"terms": {
"field": "shape.keyword"
}
}
}
}
' | jq .
{
"took": 177,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 25,
"max_score": 0,
"hits": []
},
"aggregations": {
"group_by_shape": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "rectangle",
"doc_count": 9
},
{
"key": "circle",
"doc_count": 8
},
{
"key": "triangle",
"doc_count": 8
}
]
}
}
}
可以看到最後結果的部分; 已經得到我們想要的分類囉!
這邊注意幾個地方
size: 0
: 因為我們在乎的是聚合後的結果, 而不是原始資料; 所以這邊size就可以等於0. 事實上, 如果您也有使用 grafana 或是 kibana, 也會發現他們也是這樣使用的.took: 177
: 代表這次搜尋花了 177 毫秒.hits: 25
: 代表總共有 25 顆球球.aggregations
: 透過聚合得到的資料都會出現在這物件裡.buckets
: 桶, 每個分類都是用桶子裝著 XD
接著再以顏色做分類
上面分類出來, 只能得到各形狀有幾顆球球; 但是我們還需要知道更細的分類
每個形狀裡面, 個別又有多少顏色的球?
這是我們想要得到的結果:
這時候, 有了上面分類的概念, 只要照著嵌套下去就行了~
所以說, 結構長成這樣:
{
聚合: {
以形狀分類: {
詞分類: {
欄位: 形狀
},
聚合: {
以顏色分類: {
詞分類: {
欄位: 顏色
}
}
}
}
}
}
實際操作
❯ curl -s -H "Content-Type: Application/json" -XPOST "http://192.168.40.41:9200/demo/_search" -d '
{
"size": 0,
"query": {
"bool": {}
},
"aggs": {
"group_by_shape": {
"terms": {
"field": "shape.keyword"
},
"aggs": {
"group_by_color": {
"terms": {
"field": "color.keyword"
}
}
}
}
}
}
' | jq .
{
"took": 65,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 25,
"max_score": 0,
"hits": []
},
"aggregations": {
"group_by_shape": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "rectangle",
"doc_count": 9,
"group_by_color": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "blue",
"doc_count": 5
},
{
"key": "red",
"doc_count": 3
},
{
"key": "yellow",
"doc_count": 1
}
]
}
},
{
"key": "circle",
"doc_count": 8,
"group_by_color": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "blue",
"doc_count": 4
},
{
"key": "red",
"doc_count": 3
},
{
"key": "yellow",
"doc_count": 1
}
]
}
},
{
"key": "triangle",
"doc_count": 8,
"group_by_color": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "yellow",
"doc_count": 6
},
{
"key": "blue",
"doc_count": 2
}
]
}
}
]
}
}
}
鏘鏘鏘~ 這樣就達到我們要的結果了~ 如果說每個球球身上還有分數的話, 還可以繼續嵌套下去將它計算出來唷!
所以上面得答案依序是
- 這一坨球球裡面有哪些形狀?
rectangle, triangle, circle
- 每個形狀有幾顆球球?
rectangle:9, triangle:8, circle: 8
- 每個形狀, 有幾個不同顏色的球球?
rectangle-blue: 5, rectangle-red: 3, rectangle-yellow: 1
triangle-blue: 2, triangle-red: 0, triangle-yellow: 6
circle-blue: 4, circle-red: 3, circle-yellow: 1
分組聚合就到這邊告一段落囉, 謝謝大家.