http://www.cnblogs.com/xing901022/p/4947436.htmlhtml
ES中的聚合被分爲兩大類:Metric度量和bucket桶。說的通俗點,metric很像SQL中的avg、max、min
等方法,而bucket就有點相似group by
了。數組
metric的聚合按照值的返回類型能夠分爲兩種:單值聚合 和 多值聚合。spa
這個聚合返回的是單個值,dsl能夠參考以下:code
"aggs" : {orm
"intraday_return" : { "sum" : { "field" : "change" } }htm
}blog
intraday_return是聚合的名字,同時也會做爲請求返回的id值。另外,聚合中是支持腳本的。排序
{ip
...內存
"aggregations": {
"intraday_return": {
"value": 2.18
}
}
}
{
"aggs" : {
"min_price" : { "min" : { "field" : "price" } }
}
}
{
"aggs" : {
"max_price" : { "max" : { "field" : "price" } }
}
}
{
"aggs" : {
"avg_grade" : { "avg" : { "field" : "grade" } }
}
}
{
"aggs" : {
"author_count" : {
"cardinality" : {
"field" : "author"
}
}
}
}
{
"aggs" : {
"load_time_outlier" : {
"percentile_ranks" : {
"field" : "load_time",
"values" : [15, 30]
}
}
}
}
返回結果:
{
...
"aggregations": {
"load_time_outlier": {
"values" : {
"15": 92,
"30": 100
}
}
}
}
{
"aggs" : {
"grades_stats" : { "stats" : { "field" : "grade" } }
}
}
返回結果:
{
...
"aggregations": {
"grades_stats": {
"count": 6,
"min": 60,
"max": 98,
"avg": 78.5,
"sum": 471
}
}
}
{
"aggs" : {
"grades_stats" : { "extended_stats" : { "field" : "grade" } }
}
}
返回結果:
{
...
"aggregations": {
"grade_stats": {
"count": 9,
"min": 72,
"max": 99,
"avg": 86,
"sum": 774,
"sum_of_squares": 67028,
"variance": 51.55555555555556,
"std_deviation": 7.180219742846005,
"std_deviation_bounds": {
"upper": 100.36043948569201,
"lower": 71.63956051430799
}
}
}
}
Bucket能夠理解爲一個桶,它會遍歷文檔中的內容,凡是符合要求的就放入按照要求建立的桶中。
它是按照某個字段中的值來分類:好比性別有男、女,就會建立兩個桶,分別存放男女的信息。默認會蒐集doc_count的信息,即記錄有多少男生,有多少女生,而後返回給客戶端,這樣就完成了一個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
},
]
}
}
}
2.1.1 terms聚合分析:
2.1.1.1 數據的不肯定性
使用terms聚合,結果可能帶有必定的誤差與錯誤性。
舉個例子:
咱們想要獲取name字段中出現頻率最高的前5個。
此時,客戶端向ES發送聚合請求,主節點接收到請求後,會向每一個獨立的分片發送該請求。
分片獨立的計算本身分片上的前5個name,而後返回。當全部的分片結果都返回後,在主節點進行結果的合併,再求出頻率最高的前5個,返回給客戶端。這樣就會形成必定的偏差,好比最後返回的前5箇中,有一個叫A的,有50個文檔;B有49。可是因爲每一個分片獨立的保存信息,信息的分佈也是不肯定的。有可能第一個分片中B的信息有2個,可是沒有排到前5,因此沒有在最後合併的結果中出現。這就致使B的總數少計算了2,原本可能排到第一位,卻排到了A的後面。
2.1.1.2 size與shard_size
爲了改善上面的問題,就可使用size和shard_size參數。
- size參數規定了最後返回的term個數(默認是10個)
- shard_size參數規定了每一個分片上返回的個數
- 若是shard_size小於size,那麼分片也會按照size指定的個數計算
經過這兩個參數,若是咱們想要返回前5個,size=5;shard_size能夠設置大於5,這樣每一個分片返回的詞條信息就會增多,相應的偏差概率也會減少。
2.1.1.3 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" } }
}
}
}
}
2.1.1.4 min_doc_count與shard_min_doc_count
聚合的字段可能存在一些頻率很低的詞條,若是這些詞條數目比例很大,那麼就會形成不少沒必要要的計算。
所以能夠經過設置min_doc_count和shard_min_doc_count來規定最小的文檔數目,只有知足這個參數要求的個數的詞條纔會被記錄返回。經過名字就能夠看出:
- min_doc_count:規定了最終結果的篩選
- shard_min_doc_count:規定了分片中計算返回時的篩選
2.1.1.5 script
桶聚合也支持腳本的使用:
{
"aggs" : {
"genders" : {
"terms" : {
"script" : "doc['gender'].value"
}
}
}
}
以及外部腳本文件:
{
"aggs" : {
"genders" : {
"terms" : {
"script" : {
"file": "my_script",
"params": {
"field": "gender"
}
}
}
}
}
}
2.1.1.6 filter
filter字段提供了過濾的功能,使用兩種方式:include能夠過濾出包含該值的文檔;相反則使用exclude。
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"include" : ".*sport.*",
"exclude" : "water_.*"
}
}
}
}
一般狀況,terms聚合都是僅針對於一個字段的聚合。由於該聚合是須要把詞條放入一個哈希表中,若是多個字段就會形成n^2的內存消耗。
不過,對於多字段,ES也提供了下面兩種方式:
1. 使用腳本合併字段
2. 使用copy_to方法,合併兩個字段,建立出一個新的字段,對新字段執行單個字段的聚合。
例如:實現 select SEX,PROF,COUNT(*) from table group by SEX,PROF
{
"size": 0,
"query": {
"match_all": {}
},
"aggs": {
"sexprof": { //使用腳本合併字段並對新字段執行單字段的聚合
"terms": {
"script": {
"inline": "doc['SEX.keyword'].value +'-split-'+ doc['PROF.keyword'].value "
}
}
}
}
}
獲得的結果:
{
"aggregations": {
"sexprof": {
"doc_count_error_upper_bound": 5,
"sum_other_doc_count": 379,
"buckets": [
{
"key": "女-split-助教",
"doc_count": 2
},
{
"key": "男-split-講師",
"doc_count": 1
},
{
"key": "男-split-教授",
"doc_count": 1
}
]
}
}
}
對於子聚合的計算,有兩種方式:
默認狀況下ES會使用深度優先,不過能夠手動設置成廣度優先,好比:
{
"aggs" : {
"actors" : {
"terms" : {
"field" : "actors",
"size" : 10,
"collect_mode" : "breadth_first"
},
"aggs" : {
"costars" : {
"terms" : {
"field" : "actors",
"size" : 5
}
}
}
}
}
}
缺省值指定了缺省的字段的處理方式:
{
"aggs" : {
"tags" : {
"terms" : {
"field" : "tags",
"missing": "N/A"
}
}
}
}
Elasticsearch支持最直方圖聚合,它在數字字段自動建立桶,並會掃描所有文檔,把文檔放入相應的桶中。這個數字字段既能夠是文檔中的某個字段,也能夠經過腳本建立得出的。
返回document數量大於等於1 的直方圖聚合
{
"aggs" : {
"prices" : {
"histogram" : {
"field" : "price",
"interval" : 50,
"min_doc_count" : 1
}
}
}
}
默認狀況下,ES中的histogram聚合起始都是自動的,好比price字段,若是沒有商品的價錢在0-5之間,0這個桶就不會顯示。若是最便宜的商品是11,那麼第一個桶就是10.
能夠經過設置extend_bounds強制規定最小值和最大值,可是要求必須min_doc_count不能大於0,否則即使是規定了邊界,也不會返回。
能夠經過設置extend_bounds強制規定最小值和最大值,可是要求必須min_doc_count不能大於0,否則即使是規定了邊界,也不會返回。
排序大同小異,能夠按照_key,_count,指定排序的聚合進行排序
{
"aggs" : {
"prices" : {
"histogram" : {
"field" : "price",
"interval" : 50,
"order" : { "_key" : "desc" }
}
}
}
}
正常返回的數據如上面所示,是按照數組的方式返回。若是要按照名字返回,能夠設置keyed爲true。
以前的返回方式:
設置keyed爲true:
{
"aggs" : {
"prices" : {
"histogram" : {
"field" : "price",
"interval" : 50,
"keyed" : true
}
}
}
}
返回的數據爲:
{ "aggregations": { "prices": { "buckets": { "0": { "key": 0, "doc_count": 2 }, "50": { "key": 50, "doc_count": 4 }, "150": { "key": 150, "doc_count": 3 } } } } }
缺省值經過MissingValue設置:
{
"aggs" : {
"quantity" : {
"histogram" : {
"field" : "quantity",
"interval": 10,
"missing": 0
}
}
}
}
Date histogram的用法與histogram差很少,只不過區間上支持了日期的表達式。
{
"aggs":{
"articles_over_time":{
"date_histogram":{
"field":"date",
"interval":"month"
}
}
}
}
interval字段支持多種關鍵字:`year`, `quarter`, `month`, `week`, `day`, `hour`, `minute`, `second`
也支持對這些關鍵字進行擴展使用,好比一個半小時能夠定義成以下::
{
"aggs":{
"articles_over_time":{
"date_histogram":{
"field":"date",
"interval":"1.5h"
"format":"yyyy-MM-dd" //對返回結果進行格式化
}
}
}
}
在es中日期支持時區的表示方法,這樣就至關於東八區的時間。
{
"aggs":{
"by_day":{
"date_histogram":{
"field":"date",
"interval":"day",
"time_zone":"+08:00"
}
}
}
}
默認狀況是從凌晨0點到午夜24:00,若是想改變時間區間,能夠經過下面的方式,設置偏移值:
{
"aggs":{
"by_day":{
"date_histogram":{
"field":"date",
"interval":"day",
"offset":"+6h"
}
}
}
}
當遇到沒有值的字段,就會按照缺省字段missing value來計算。
對於其餘的一些用法,這裏就不過多贅述了,好比腳本、Order、min_doc_count過濾,extended_bounds等都是支持的。
{
"aggs": {
"missing_address": {
"missing": {
"field": "address"
}
}
}
}
結果只返回一個桶
{
"aggs":{
"color_type_max":{
"terms":{
"field": "color"
},
"aggs":{
"max_age": {
"max": {
"field" : "age"
}
}
}
},
"color_type_min":{
"terms":{
"field": "color"
},
"aggs":{
"min_age": {
"min": {
"field" : "age"
}
}
}
}
}
}