聚合概念
ElasticSearch除了致力於搜索之外,也提供了聚合實時分析數據的功能
如果把搜索比喻為大海撈針(從海量的文檔中找出符合條件的那一個),那麽聚合就是去分析大海中的針們的特性,像是
在大海里有多少針?
針的平均長度是多少?
按照針的製造商來划分,針的長度中位值是多少?
每月加入到海中的針有多少?
這里面有異常的針麽?
因此透過聚合,我們可以得到一個數據的概覽,聚合能做的是分析和總結全套的數據,而不是查找單個文檔(這是搜索做的事)
聚合允許我們向數據提出一些複雜的問題,雖然他的功能完全不同於搜索,但他們其實使用了相同的數據結構,這表示聚合的執行速度很快,並且就像搜索一樣幾乎是實時的
並且由於聚合和搜索是使用同樣的數據結構,因此聚合和搜索可以是一起執行的
這表示我們可以在一次json請求裡,同時對相同的數據進行 搜索/過濾 + 分析,兩個願望一次滿足
聚合的兩個主要的概念,分別是 桶 和 指標
桶(Buckets) : 滿足特定條件的文檔的集合
當聚合開始被執行,每個文檔會決定符合哪個桶的條件,如果匹配到,文檔將放入相應的桶並接着進行聚合操作
像是一個員工屬於男性桶或者女性桶,日期2014-10-28屬於十月桶,也屬於2014年桶
桶可以被嵌套在其他桶里面
像是北京能放在中國桶裡,而中國桶能放在亞洲桶裡
Elasticsearch提供了很多種類型的桶,像是時間、最受歡迎的詞、年齡區間、地理位置桶等等,不過他們在根本上都是通過同樣的原理進行操作,也就是基於條件來划分文檔,一個文檔只要符合條件,就可以加入那個桶,因此一個文檔可以同時加入很多桶
指標(Metrics) : 對桶內的文檔進行統計計算
桶能讓我們划分文檔到有意義的集合, 但是最終我們需要的是對這些桶內的文檔進行一些指標的計算
指標通常是簡單的數學運算(像是min、max、avg、sum),而這些是通過當前桶中的文檔的值來計算的,利用指標能讓你計算像平均薪資、最高出售價格、95%的查詢延遲這樣的數據
aggs 聚合的模板
當query和aggs一起存在時,會先執行query的主查詢,主查詢query執行完后會搜出一批結果,而這些結果才會被拿去aggs拿去做聚合
另外要注意aggs后面會先接一層自定義的這個聚合的名字,然后才是接上要使用的聚合桶
如果有些情況不在意查詢結果是什麽,而只在意aggs的結果,可以把size設為0,如此可以讓返回的hits結果集是0,加快返回的速度
一個aggs裡可以有很多個聚合,每個聚合彼此間都是獨立的,因此可以一個聚合拿來統計數量、一個聚合拿來分析數據、一個聚合拿來計算標准差...,讓一次搜索就可以把想要做的事情一次做完
像是此例就定義了3個聚合,分別是custom_name1、custom_name2、custom_name3
aggs可以嵌套在其他的aggs裡面,而嵌套的桶能作用的文檔集范圍,是外層的桶所輸出的結果集
GET 127.0.0.1/mytest/doc/_search
{
"query": { ... },
"size": 0,
"aggs": {
"custom_name1": { //aggs后面接著的是一個自定義的name
"桶": { ... } //再來才是接桶
},
"custom_name2": { //一個aggs裡可以有很多聚合
"桶": { ... }
},
"custom_name3": {
"桶": {
.....
},
"aggs": { //aggs可以嵌套在別的aggs裡面
"in_name": { //記得使用aggs需要先自定義一個name
"桶": { ... } //in_name的桶作用的文檔是custom_name3的桶的結果
}
}
}
}
}
結果
{
"hits": {
"total": 8,
"max_score": 0,
"hits": [] //因為size設為0,所以沒有查詢結果返回
},
"aggregations": {
"custom_name1": {
...
},
"custom_name2": {
...
},
"custom_name3": {
... ,
"in_name": {
....
}
}
}
}
聚合中常用的桶 terms、filter、top_hits
terms桶 : 針對某個field的值進行分組,field有幾種值就分成幾組
terms桶在進行分組時,會爲此field中的每種值創建一個新的桶
要注意此 "terms桶" 和平常用在主查詢query中的 "查找terms" 是不同的東西
具體實例
首先插入幾筆數據,其中color是一個keyword類型
{ "color": "red" }
{ "color": "green" }
{ "color": ["red", "blue"] }
執行terms聚合
GET 127.0.0.1/mytest/doc/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"my_name": {
"terms": {
"field": "color" //使用color來進行分組
}
}
}
}
結果
因為color總共有3種值,red、blue、green,所以terms桶為他們產生了3個bucket,並計算了每個bucket中符合的文檔有哪些
bucket和bucket間是獨立的,也就是說一個文檔可以同時符合好幾個bucket,像是{"color": ["red", "blue"]}就同時符合了red和blue bucket
"aggregations": {
"my_name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "blue",
"doc_count": 1
},
{
"key": "red",
"doc_count": 2 //表示color為red的文檔有2個,此例中就是 {"color": "red"} 和 {"color": ["red", "blue"]}這兩個文檔
},
{
"key": "green",
"doc_count": 1
}
]
}
}
具體實例二
將terms桶搭配度量指標(avg、min、max、sum...)一起使用
其實度量指標也可以看成一種"桶",他可以和其他正常的桶們進行嵌套作用,差別只在指標關注的是這些文檔中的某個數值的統計,而桶關注的是文檔
首先准備數據,color一樣為keyword類型,而price為integer類型
{ "color": "red", "price": 100 }
{ "color": "green", "price": 500 }
{ "color": ["red", "blue"], "price": 1000 }
將avg指標嵌套在terms桶裡一起使用
GET 127.0.0.1/mytest/doc/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"my_name": {
"terms": {
"field": "color"
},
"aggs": { //嵌套兩個指標avg、min在terms桶中
"my_avg_price": { //my_avg_price計算每個bucket的平均price
"avg": {
"field": "price"
}
},
"my_min_price": { //my_min_price計算每個bucket中的最小price
"min": {
"field": "price"
}
}
}
}
}
}
結果
"aggregations": {
"my_name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [ //terms桶中的每個bucket都會計算avg和min兩個指標
{
"key": "blue",
"doc_count": 1,
"my_avg_price": { //avg指標
"value": 1000
},
"my_min_price": { //min指標
"value": 100
}
},
{
"key": "red",
"doc_count": 2,
"my_avg_price": { //avg指標計算的值,因為符合color為red的文檔有兩筆,所以平均price為100+1000/2 = 550
"value": 550
},
"my_min_price": {
"value": 100
}
},
{
"key": "green",
"doc_count": 1,
"my_avg_price": {
"value": 500
},
"my_min_price": {
"value": 500
}
}
]
}
}
filter桶 : 一個用來過濾的桶
要注意此處的 "filter桶" 和用在主查詢query的 "過濾filter" 的用法是一模一樣的,都是過濾
不過差別是 "filter桶" 會自己給創建一個新的桶,而不會像 "過濾filter" 一樣依附在query下
因為filter桶畢竟還是一個聚合桶,因此他可以和別的桶進行嵌套,但他不是依附在別的桶上
具體實例
取得color為red或是blue的文檔
GET 127.0.0.1/mytest/doc/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"my_name": {
"filter": { //因為他用法跟一般的過濾filter一樣,所以也能使用bool嵌套
"bool": {
"must": {
"terms": { //注意此terms是查找terms,不是terms桶
"color": [ "red", "blue" ]
}
}
}
}
}
}
}
結果
"aggregations": {
"my_name": {
"doc_count": 2 //filter桶計算出來的文檔數量
}
}
具體實例二
filter桶和terms桶嵌套使用,先過濾出color為red以及blue的文檔,再對這些文檔進行color分組
GET 127.0.0.1/mytest/doc/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"my_name": { //my_name聚合
"filter": { //filter桶
"bool": {
"must": {
"terms": {
"color": [ "red", "blue" ]
}
}
}
},
"aggs": {
"my_name2": { //my_name2聚合,嵌套在my_name聚合裡
"terms": { //terms桶
"field": "color"
}
}
}
}
}
}
結果
因為terms桶嵌套在filter桶內,所以query查詢出來的文檔們會先經過filter桶,如果符合filter桶,才會進入到terms桶內
此處通過filter桶的文檔只有兩筆,分別是{"color": "red"}以及{"color": ["red", "blue"]},所以terms桶只會對這兩筆文檔做分組
這也是為什麽terms桶裡沒有出現color為green的分組,因為這個文檔在filter桶就被擋下來了
"aggregations": {
"my_name": {
"doc_count": 2, //filter桶計算的數量,通過此處的文檔只有2筆
"my_name2": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "red",
"doc_count": 2 //terms桶計算的數量
},
{
"key": "blue",
"doc_count": 1 //terms桶計算的數量
}
]
}
}
}
top_hits桶 : 在某個桶底下找出這個桶的前幾筆hits,返回的hits格式和主查詢query返回的hits格式一模一樣
top_hits桶支持的參數
from、size
sort : 設置返回的hits的排序
要注意,假設在主查詢query裡已經對數據設置了排序sort,此sort並不會對aggs裡面的數據造成影響,也就是說主查詢query查找出來的數據會先丟進aggs而非先經過sort,因此就算主查詢設置了sort,也不會影響aggs數據裡的排序
因此如果在top_hits桶裡的返回的hits數據想要排序,需要自己在top_hits桶裡設置sort
如果沒有設置sort,默認使用主查詢query所查出來的_score排序
_source : 設置返回的字段
具體實例
首先准備數據,color是keyword類型
{ "color": "red", "price": 100 }
{ "color": ["red", "blue"], "price": 1000 }
使用terms桶分組,再使用top_hits桶找出每個group裡面的price最小的前5筆hits
GET 127.0.0.1/mytest/doc/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"my_name": {
"terms": {
"field": "color"
},
"aggs": {
"my_top_hits": {
"top_hits": {
"size": 5,
"sort": {
"price": "asc"
}
}
}
}
}
}
}
結果
"aggregations": {
"my_name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "red",
"doc_count": 2, //terms桶計算出來的color為red的文檔數
"my_top_hits": {
"hits": { //top_hits桶找出color為red的這些文檔中,price從小到大排序取前5筆
"total": 2,
"max_score": null,
"hits": [
{
"_score": null,
"_source": { "color": "red", "price": 100 },
"sort": [ 100 ]
},
{
"_score": null,
"_source": { "color": [ "red", "blue" ], "price": 1000 },
"sort": [ 1000 ]
}
]
}
}
},
{
"key": "blue",
"doc_count": 1, //terms桶計算出來的color為blue的文檔數
"my_top_hits": {
"hits": { //top_hits桶找出的hits
"total": 1,
"max_score": null,
"hits": [
{
"_source": {
"color": [ "red", "blue" ], "price": 1000 },
"sort": [ 1000 ]
}
]
}
}
}
]
}
}
多桶排序
terms桶、histogram桶、data_histogram桶這些桶屬於多值桶,也就是說他們會動態生成很多桶,對於這些生成出來的桶們,Elasticsearch默認會使用doc_value進行降序排序,也就是說哪個生成桶的doc_value文檔數較多,哪個生成桶就排在前面
如果想要改變這個生成桶與生成桶之間的排序,可以在使用terms桶、histogram桶、data_histogram桶時,使用order進行排序
order支持的參數
_count : 按照文檔數排序
_key : 按照每個桶的字符串值的字母順序排序
具體實例
准備數據,color是keyword類型
{ "color": "red", "price": 100 }
{ "color": ["red", "blue"], "price": 1000 }
使用terms桶進行分組,並且規定按照桶的字母順序升序,因此a生成桶會排在最前面而z生成桶會排在最后面
GET 127.0.0.1/mytest/doc/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"my_name": {
"terms": {
"field": "color",
"order": {
"_key": "asc"
}
}
}
}
}
結果
"aggregations": {
"my_name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "blue",
"doc_count": 1
},
{
"key": "red",
"doc_count": 2
}
]
}
}
點贊 5
————————————————
版權聲明:本文為CSDN博主「古古說」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_40341116/article/details/81173016
