Elasticsearch聚合 之 Terms
本篇著重講解的terms聚合,它是按照某個字段中的值來分類:
比如性別有男、女,就會創建兩個桶,分別存放男女的信息。默認會搜集doc_count的信息,即記錄有多少男生,有多少女生,然後返回給客戶端,這樣就完成了一個terms得統計。
Terms聚合
{
"aggs" : {
"genders" : {
"terms" : { "field" : "gender" }
}
}
}
得到的結果如下:
{
...
"aggregations" : {
"genders" : {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets" : [
{
"key" : "male",
"doc_count" : 10
},
{
"key" : "female",
"doc_count" : 10
},
]
}
}
}
數據的不確定性
使用terms聚合,結果可能帶有一定的偏差與錯誤性。
舉個例子:
我們想要獲取name字段中出現頻率最高的前5個。
此時,客戶端向ES發送聚合請求,主節點接收到請求後,會向每個獨立的分片發送該請求。
分片獨立的計算自己分片上的前5個name,然後返回。當所有的分片結果都返回後,在主節點進行結果的合並,再求出頻率最高的前5個,返回給客戶端。
這樣就會造成一定的誤差,比如最後返回的前5個中,有一個叫A的,有50個文檔;B有49。但是由於每個分片獨立的保存信息,信息的分布也是不確定的。有可能第一個分片中B的信息有2個,但是沒有排到前5,所以沒有在最後合並的結果中出現。這就導致B的總數少計算了2,本來可能排到第一位,卻排到了A的後面。
size與shard_size
為了改善上面的問題,就可以使用size和shard_size參數。
- size參數規定了最後返回的term個數(默認是10個)
- shard_size參數規定了每個分片上返回的個數
- 如果shard_size小於size,那麽分片也會按照size指定的個數計算
通過這兩個參數,如果我們想要返回前5個,size=5;shard_size可以設置大於5,這樣每個分片返回的詞條信息就會增多,相應的誤差幾率也會減小。
order排序
order指定了最後返回結果的排序方式,默認是按照doc_count排序。
{
"aggs" : {
"genders" : {
"terms" : {
"field" : "gender",
"order" : { "_count" : "asc" }
}
}
}
}
也可以按照字典方式排序:
{
"aggs" : {
"genders" : {
"terms" : {
"field" : "gender",
"order" : { "_term" : "asc" }
}
}
}
}
當然也可以通過order指定一個單值的metric聚合,來排序。
{
"aggs" : {
"genders" : {
"terms" : {
"field" : "gender",
"order" : { "avg_height" : "desc" }
},
"aggs" : {
"avg_height" : { "avg" : { "field" : "height" } }
}
}
}
}
同時也支持多值的Metric聚合,不過要指定使用的多值字段:
{
"aggs" : {
"genders" : {
"terms" : {
"field" : "gender",
"order" : { "height_stats.avg" : "desc" }
},
"aggs" : {
"height_stats" : { "stats" : { "field" : "height" } }
}
}
}
}
min_doc_count與shard_min_doc_count
聚合的字段可能存在一些頻率很低的詞條,如果這些詞條數目比例很大,那麽就會造成很多不必要的計算。
因此可以通過設置min_doc_count和shard_min_doc_count來規定最小的文檔數目,只有滿足這個參數要求的個數的詞條才會被記錄返回。
通過名字就可以看出:
- min_doc_count:規定了最終結果的篩選
- shard_min_doc_count:規定了分片中計算返回時的篩選
script
桶聚合也支持腳本的使用:
{
"aggs" : {
"genders" : {
"terms" : {
"script" : "doc[‘gender‘].value"
}
}
}
}
以及外部腳本文件:
{
"aggs" : {
"genders" : {
"terms" : {
"script" : {
"file": "my_script",
"params": {
"field": "gender"
}
}
}
}
}
}
filter
filter字段提供了過濾的功能,使用兩種方式:include可以過濾出包含該值的文檔;相反則使用exclude。
例如:
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"include" : ".*sport.*",
"exclude" : "water_.*"
}
}
}
}
上面的例子中,最後的結果應該包含sport並且不包含water。
也支持數組的方式,定義包含與排除的信息:
{
"aggs" : {
"JapaneseCars" : {
"terms" : {
"field" : "make",
"include" : ["mazda", "honda"]
}
},
"ActiveCarManufacturers" : {
"terms" : {
"field" : "make",
"exclude" : ["rover", "jensen"]
}
}
}
}
多字段聚合
通常情況,terms聚合都是僅針對於一個字段的聚合。因為該聚合是需要把詞條放入一個哈希表中,如果多個字段就會造成n^2的內存消耗。
不過,對於多字段,ES也提供了下面兩種方式:
- 1 使用腳本合並字段
- 2 使用copy_to方法,合並兩個字段,創建出一個新的字段,對新字段執行單個字段的聚合。
collect模式
對於子聚合的計算,有兩種方式:
- depth_first 直接進行子聚合的計算
- breadth_first 先計算出當前聚合的結果,針對這個結果在對子聚合進行計算。
默認情況下ES會使用深度優先,不過可以手動設置成廣度優先,比如:
{
"aggs" : {
"actors" : {
"terms" : {
"field" : "actors",
"size" : 10,
"collect_mode" : "breadth_first"
},
"aggs" : {
"costars" : {
"terms" : {
"field" : "actors",
"size" : 5
}
}
}
}
}
}
缺省值Missing value
缺省值指定了缺省的字段的處理方式:
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"missing": "N/A"
}
}
}
}
Elasticsearch聚合 之 Terms