聚合的范圍是search query過濾出的數據
四種聚合類型:
一、Bucketing
桶聚合,常規的分類然后計算每個分類的文檔數量
二、Metric
分類並對一組文檔進行sum、avg等數學運算
三、Matrix
可在多個字段上計算,生成矩陣結果
四、Pipeline
對聚合的結果再次聚合
Pipeline aggregations 會在所有的聚類執行完畢之后才執行
聚合語句的結構
"aggs" : {
"<aggregation_name>" : {
"<aggregation_type>" : {
<aggregation_body>
}
[,"meta" : { [<meta_data_body>] } ]?
[,"aggregations" : { [<sub_aggregation>]+ } ]?
}
[,"<aggregation_name_2>" : { ... } ]*
}
Terms Aggregation
會根據字段的值動態構建buckets
{
"aggs" : {
"genres" : {
"terms" : { "field" : "genre" }
}
}
}
返回:
{
...
"aggregations" : {
"genres" : {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets" : [
{
"key" : "jazz",
"doc_count" : 10
},
{
"key" : "rock",
"doc_count" : 10
},
{
"key" : "electronic",
"doc_count" : 10
},
]
}
}
}
當字段的值很多的時候,elasticsearch只會返回部分buckets,sum_other_doc_count
表示沒有被返回的 buckets 中 document 的數量之和
size
默認情況下,elasticsearch只會返回按照doc_count降序排序的前10個terms,可以配置size
參數來修改這一默認行為
terms聚合的結果是不精確的
https://mp.weixin.qq.com/s/V4cGqvkQ7-DgeSvPSketgQ
比如設置size = 3
,表示希望返回TOP3
的結果
每個索引分片會取自己分片上TOP3
返回協調節點,協調節點匯總后再取匯總結果的TOP3
因此,這個結果是跟全量取TOP3
不一樣的,所以說terms聚合的結果是不精確的
size 和 shard_size 有什么區別?
- size:是聚合結果的返回值,客戶期望返回聚合排名前三,size值就是 3。
- shard_size: 每個分片上聚合的數據條數。shard_size 原則上要大於等於 size(若設置小於size,實則沒有意義,elasticsearch 會默認置為size)
請求的size值越高,結果將越准確,但計算最終結果的成本也將越高。
推薦設置 shard_size 為比較大的值,官方推薦:size*1.5+10
Order
buckets的排序可以由order
參數定義
按doc數量升序排序:
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "_count" : "asc" }
}
}
}
}
按terms的字符升序排序:
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "_term" : "asc" }
}
}
}
}
按子聚類的結果排序:
{
"aggs" : {
"genres" : {
"terms" : {
"field" : "genre",
"order" : { "max_play_count" : "desc" }
},
"aggs" : {
"max_play_count" : { "max" : { "field" : "play_count" } }
}
}
}
}
min_doc_count
默認值為1,表示只返回doc_count大於等於1的buckets
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"min_doc_count": 10
}
}
}
}
Nested Aggregation
針對nested
字段的聚合,比如
{
...
"product" : {
"properties" : {
"resellers" : {
"type" : "nested",
"properties" : {
"name" : { "type" : "text" },
"price" : { "type" : "double" }
}
}
}
}
}
求價格最低的產品的聚合語句可以寫成:
{
"query" : {
"match" : { "name" : "led tv" }
},
"aggs" : {
"resellers" : {
"nested" : {
"path" : "resellers"
},
"aggs" : {
"min_price" : { "min" : { "field" : "resellers.price" } }
}
}
}
}
需要在頂層聚類的path字段填入nested
的字段名稱,然后,在子聚類中再針對子字段聚類
Date Histogram Aggregation 日期直方圖
比如,想要統計每天的商品銷量
GET /goods/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"date_list": {
"gte": "2020-8-1",
"lt": "2020-8-2"
}
}
}
]
}
},
"size": 0,
"aggs": {
"date_count": {
"date_histogram": {
"field": "date_list",
"format": "yyyy-MM-dd",
"interval": "day"
}
}
}
}
根據過濾的結果數據,以天為間隔聚類繪制直方圖
{
"took": 82,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 34841,
"max_score": 0,
"hits": []
},
"aggregations": {
"date_count": {
"buckets": [
{
"key_as_string": "2020-06-02",
"key": 1591056000000,
"doc_count": 17
},
{
"key_as_string": "2020-06-03",
"key": 1591142400000,
"doc_count": 387
},
...
會出現6月的聚類結果是因為date_list
是一組數據,可能某個document的這個字段即包含8月2日又包含6月2日,那么它將即被放到8-2的桶也被放到6-2的桶
時間間隔
時間間隔單位的可選項:year, quarter, month, week, day, hour, minute, second
精確指定時間間隔:1.5h
也可以寫成90m
時間格式
在es內部,日期被表示為一個64位的時間戳(milliseconds-since-the-epoch),這正是bucket key字段的值。key_as_string
字段的格式可以由format
參數決定
如果不指定format
,則es會選此字段mapping的第一個日期格式
offset
當使用day作為時間間隔的時候,每個桶的范圍是0點至0點,設置offset
為+6h
表示將桶的范圍改為6am to 6am
GET my_index/_search?size=0
{
"aggs": {
"by_day": {
"date_histogram": {
"field": "date",
"interval": "day",
"offset": "+6h"
}
}
}
}
Keyed Response
將keyed
標簽置為true
表示bucket將以hashmap格式返回,key_as_string
作為key
POST /sales/_search?size=0
{
"aggs" : {
"sales_over_time" : {
"date_histogram" : {
"field" : "date",
"interval" : "1M",
"format" : "yyyy-MM-dd",
"keyed": true
}
}
}
}
Response:
{
...
"aggregations": {
"sales_over_time": {
"buckets": {
"2015-01-01": {
"key_as_string": "2015-01-01",
"key": 1420070400000,
"doc_count": 3
},
"2015-02-01": {
"key_as_string": "2015-02-01",
"key": 1422748800000,
"doc_count": 2
},
"2015-03-01": {
"key_as_string": "2015-03-01",
"key": 1425168000000,
"doc_count": 2
}
}
}
}
}
Missing value
如果不定義missing
,date
字段缺失的文檔將被忽略。這樣定義后,這些文檔會被歸入2000/01/01
桶
POST /sales/_search?size=0
{
"aggs" : {
"sale_date" : {
"date_histogram" : {
"field" : "date",
"interval": "year",
"missing": "2000/01/01"
}
}
}
}
根據聚合的結果進行過濾
https://elasticsearch.cn/article/13501
每個IP登錄次數超過5次的IP
{
"aggs": {
"IP": {
"terms": {
"field": "IP",
"size": 3000,
"order": {
"_count": "desc"
},
"min_doc_count": 5
}
}
},
"size": 0
}
會篩選出大於或等於5的buckets
每個IP登錄人數超過2的IP
{
"aggs": {
"IP": {
"terms": {
"field": "IP",
"size": 3000,
"order": {
"distinct": "desc"
},
"min_doc_count": 5
},
"aggs": {
"distinct": {
"cardinality": {
"field": "IP.keyword"
}
},
"dd":{
"bucket_selector": {
"buckets_path": {"userCount":"distinct"},
"script": "params.userCount > 2"
}
}
}
}
},
"size": 0
}
bucket_selector
必須出現在子聚合中,並且只能針對子聚合的數字結果過濾,script必須返回一個bool
Post Filter
post filter允許用戶在執行聚合函數之后再對hits
做過濾,比如:
GET /shirts/_search
{
"query": {
"bool": {
"filter": {
"term": { "brand": "gucci" }
}
}
},
"aggs": {
"colors": {
"terms": { "field": "color" }
},
"color_red": {
"filter": {
"term": { "color": "red" }
},
"aggs": {
"models": {
"terms": { "field": "model" }
}
}
}
},
"post_filter": {
"term": { "color": "red" }
}
}
由於aggs的范圍取決於query,因此不能在一開始就過濾出顏色為紅色的