說明
:該博客對於的Elasticsearch 的版本爲7.3。html
在Mysql中,咱們能夠獲取一組數據的 最大值(Max)、最小值(Min)。一樣咱們可以對這組數據進行 分組(Group)。那麼對於Elasticsearch中java
咱們也能夠實現一樣的功能,聚合有關資料官方文檔內容較多,這裏大概分兩篇博客寫這個有關Elasticsearch聚合。mysql
官方對聚合有四個關鍵字: Metric(指標)
、Bucketing(桶)
、Matrix(矩陣)
、Pipeline(管道)
。sql
概念
Elasticsearch除全文檢索功能外提供的針對Elasticsearch數據作統計分析的功能。它的實時性高,全部的計算結果都是即時返回。
Elasticsearch將聚合分析主要分爲以下4類:json
Metric(指標): 指標分析類型,如計算最大值、最小值、平均值等等 (對桶內的文檔進行聚合分析的操做) Bucket(桶): 分桶類型,相似SQL中的GROUP BY語法 (知足特定條件的文檔的集合) Pipeline(管道): 管道分析類型,基於上一級的聚合分析結果進行在分析 Matrix(矩陣): 矩陣分析類型(聚合是一種面向數值型的聚合,用於計算一組文檔字段中的統計信息)
在查詢請求體中以aggregations節點按以下語法定義聚合分析:數組
"aggregations" : { "<aggregation_name>" : { <!--聚合的名字 --> "<aggregation_type>" : { <!--聚合的類型 --> <aggregation_body> <!--聚合體:對哪些字段進行聚合 --> } [,"meta" : { [<meta_data_body>] } ]? <!--元 --> [,"aggregations" : { [<sub_aggregation>]+ } ]? <!--在聚合裏面在定義子聚合 --> } [,"<aggregation_name_2>" : { ... } ]* <!--聚合的名字 --> }
說明
:aggregations 也可簡寫爲 aggsapp
雖然Elasticsearch有四種聚合方式,但在通常實際開發中,用到的比較多的就是Metric和Bucket。elasticsearch
(1) 桶(bucket) ide
a、簡單來講桶就是知足特定條件的文檔的集合。測試
b、當聚合開始被執行,每一個文檔裏面的值經過計算來決定符合哪一個桶的條件,若是匹配到,文檔將放入相應的桶並接着開始聚合操做。
c、桶也能夠被嵌套在其餘桶裏面。
(2)指標(metric)
a、桶能讓咱們劃分文檔到有意義的集合,可是最終咱們須要的是對這些桶內的文檔進行一些指標的計算。分桶是一種達到目的地的手段:它提供了一種給文檔分組的方法來讓
咱們能夠計算感興趣的指標。
b、大多數指標是簡單的數學運算(如:最小值、平均值、最大值、彙總),這些是經過文檔的值來計算的。
官網
: 指標聚合官網文檔:Metric
Metric聚合分析分爲單值分析和多值分析兩類:
#一、單值分析,只輸出一個分析結果 min,max,avg,sum,cardinality #二、多值分析,輸出多個分析結果 stats,extended_stats,percentile,percentile_rank,top hits
計算從聚合文檔中提取的數值的平均值。
POST /exams/_search?size=0 { "aggs" : { "avg_grade" : { "avg" : { "field" : "grade" } } } }
計算從聚合文檔中提取的數值的最大值。
POST /sales/_search?size=0 { "aggs" : { "max_price" : { "max" : { "field" : "price" } } } }
計算從聚合文檔中提取的數值的最小值。
POST /sales/_search?size=0 { "aggs" : { "min_price" : { "min" : { "field" : "price" } } } }
計算從聚合文檔中提取的數值的總和。
POST /sales/_search?size=0 { "query" : { "constant_score" : { "filter" : { "match" : { "type" : "hat" } } } }, "aggs" : { "hat_prices" : { "sum" : { "field" : "price" } } } }
cardinality 求惟一值,即不重複的字段有多少(至關於mysql中的distinct)
POST /sales/_search?size=0 { "aggs" : { "type_count" : { "cardinality" : { "field" : "type" } } } }
stats 統計,請求後會直接顯示多種聚合結果
POST /exams/_search?size=0 { "aggs" : { "grades_stats" : { "stats" : { "field" : "grade" } } } }
返回
{ ... "aggregations": { "grades_stats": { "count": 2, "min": 50.0, "max": 100.0, "avg": 75.0, "sum": 150.0 } } }
對指定字段的值按從小到大累計每一個值對應的文檔數的佔比,返回指定佔比比例對應的值。
1)默認取百分比
默認按照[ 1, 5, 25, 50, 75, 95, 99 ]來統計
GET latency/_search { "size": 0, "aggs" : { "load_time_outlier" : { "percentiles" : { "field" : "load_time" } } } }
返回結果能夠理解爲:佔比爲50%的文檔的age值 <= 445,或反過來:age<=445的文檔數佔總命中文檔數的50%
{ ... "aggregations": { "load_time_outlier": { "values" : { "1.0": 5.0, "5.0": 25.0, "25.0": 165.0, "50.0": 445.0, "75.0": 725.0, "95.0": 945.0, "99.0": 985.0 } } } }
2)指定分位值
GET latency/_search { "size": 0, "aggs" : { "load_time_outlier" : { "percentiles" : { "field" : "load_time", "percents" : [95, 99, 99.9] } } } }
3) Keyed Response
默認狀況下,keyed標誌設置爲true,它將惟一的字符串鍵與每一個存儲桶相關聯,並將範圍做爲哈希而不是數組返回。
GET latency/_search { "size": 0, "aggs": { "load_time_outlier": { "percentiles": { "field": "load_time", "keyed": false } } } }
返回結果
{ ... "aggregations": { "load_time_outlier": { "values": [ { "key": 1.0, "value": 5.0 }, { "key": 5.0, "value": 25.0 }, { "key": 25.0, "value": 165.0 }, { "key": 50.0, "value": 445.0 }, { "key": 75.0, "value": 725.0 }, { "key": 95.0, "value": 945.0 }, { "key": 99.0, "value": 985.0 } ] } } }
上面是經過百分比求文檔值,這裏經過文檔值求百分比。
GET latency/_search { "size": 0, "aggs" : { "load_time_ranks" : { "percentile_ranks" : { "field" : "load_time", "values" : [500, 600] } } } }
返回結果
{ ... "aggregations": { "load_time_ranks": { "values" : { "500.0": 55.1, "600.0": 64.0 } } } }
結果說明
:時間小於500的文檔佔比爲55.1%,時間小於600的文檔佔比爲64%,
通常用於分桶後獲取該桶內匹配前n的文檔列表
POST /sales/_search?size=0 { "aggs": { "top_tags": { "terms": { "field": "type", #根據type進行分組 每組顯示前3個文檔 "size": 3 }, "aggs": { "top_sales_hits": { "top_hits": { "sort": [ { "date": { "order": "desc" #按照時間進行倒敘排序 } } ], "_source": { "includes": [ "date", "price" ] #只顯示文檔指定字段 }, "size" : 1 } } } } } }
下面會針對上面官方文檔的例子進行舉例說明。
1)建立索引
DELETE /employees PUT /employees/ { "mappings" : { "properties" : { "age" : { "type" : "integer" }, "gender" : { "type" : "keyword" }, "job" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 50 } } }, "name" : { "type" : "keyword" }, "salary" : { "type" : "integer" } } } }
2)添加數據
添加10條數據,每條數據包含:姓名、年齡、工做、性別、薪資
PUT /employees/_bulk { "index" : { "_id" : "1" } } { "name" : "Emma","age":32,"job":"Product Manager","gender":"female","salary":35000 } { "index" : { "_id" : "2" } } { "name" : "Underwood","age":41,"job":"Dev Manager","gender":"male","salary": 50000} { "index" : { "_id" : "3" } } { "name" : "Tran","age":25,"job":"Web Designer","gender":"male","salary":18000 } { "index" : { "_id" : "4" } } { "name" : "Rivera","age":26,"job":"Web Designer","gender":"female","salary": 22000} { "index" : { "_id" : "5" } } { "name" : "Rose","age":25,"job":"QA","gender":"female","salary":18000 } { "index" : { "_id" : "6" } } { "name" : "Lucy","age":31,"job":"QA","gender":"female","salary": 25000} { "index" : { "_id" : "7" } } { "name" : "Byrd","age":27,"job":"QA","gender":"male","salary":20000 } { "index" : { "_id" : "8" } } { "name" : "Foster","age":27,"job":"Java Programmer","gender":"male","salary": 20000} { "index" : { "_id" : "9" } } { "name" : "Gregory","age":32,"job":"Java Programmer","gender":"male","salary":22000 } { "index" : { "_id" : "10" } } { "name" : "Bryant","age":20,"job":"Java Programmer","gender":"male","salary": 9000}
POST employees/_search { "size": 0, "aggs": { "min_salary": { "min": { "field":"salary" } } } }
返回
POST employees/_search { "size": 0, "aggs": { "max_salary": { "max": { "field": "salary" } }, "min_salary": { "min": { "field": "salary" } }, "avg_salary": { "avg": { "field": "salary" } } } }
POST employees/_search { "size": 0, "aggs": { "stats_salary": { "stats": { "field":"salary" } } } }
返回
POST employees/_search { "size": 0, "aggs": { "cardinate": { "cardinality": { "field": "job.keyword" } } } }
返回
注意
咱們須要把job的類型爲keyword
類型,這樣就不會分詞,把它當成一個總體。
POST employees/_search { "size": 0, "aggs": { "load_time_outlier": { "percentiles": { "field": "salary", "percents" : [50, 99], "keyed": false } } } }
返回
發現這些工做的中位數是:21000元。
多層嵌套
根據工做類型分桶,而後按照性別分桶,計算每一個桶中工資的最高的薪資。
POST employees/_search { "size": 0, "aggs": { "Job_gender_stats": { "terms": { "field": "job.keyword" }, "aggs": { "gender_stats": { "terms": { "field": "gender" }, "aggs": { "salary_stats": { "max": { "field": "salary" } } } } } } } }
返回
一、Elasticsearch核心技術與實戰---阮一鳴(eBay Pronto平臺技術負責人
我相信,不管從此的道路多麼坎坷,只要抓住今天,早晚會在奮鬥中嚐到人生的甘甜。抓住人生中的一分一秒,賽過虛度中的一月一年!(12)