一、聚合分析的簡單介紹
- 聚合分析,英文為 Aggregation,是es 除搜尋功能外提供的針對es資料做統計分析的功能。
- es聚合分析功能豐富,提供 Bucket、Metric、Pipeline等多種分析方式,可以滿足大部分的分析需求;
- 實時性高,所有的計算結果是即時傳回的,而Hadoop 等大資料系統一般都是 T+1 級别的。
- 文法如下:
GET testindex/_search
{
"size": 0,
"aggs": { // 關鍵詞,與query 同級
"agg_name": { // 自定義的聚合名稱
"agg_type": { // 聚合分析的定義,包含type 和 body 定義
"agg_body"
},
[,"aggs": {"sub_agg"}] // 子聚合
},
"agg_name2": {....} // 可以包含多個聚合
}
}
二、聚合分析之分類
- Bucket,分桶類型,類似 SQL 中的 group by 文法;
- Metric,名額分析類型,如計算最大值、最小值、平均值等;
- Pipeline,管道分析類型,基于上一級的聚合分析結果進行再分析;
- Matrix,矩陣分析類型。
三、Bucket 聚合分析
Bucket,意味 ’桶‘,即按照一定的規則将文檔配置設定到不同的桶中,達到分類的目的。
按照Bucket 的分桶政策,常見的Bucket 聚合分析如下:
- Terms:直接按照term來分桶。如果是text 類型(需要開啟fielddata),則按照分詞後的結果分桶。
- Range:通過制定數值的範圍内設定分桶規則
// *-10000,10000-20000,20000-* 三個區間的文檔數聚合 GET testinde/_search { "aggs": { "salary_range": { "range": { "field": "salary", "ranges": [ { "key": "<10000", // 自定義key 值的名字 "to": 10000 }, { "from": 10000, "to": 20000, }, { "from": 20000 } ] } } } }
- Date Range:通過制定日期的範圍來設定分桶規則
GET testindex/_search
{
"aggs": {
"date_range": {
"range": {
"field": "birth",
"format": "yyyy-MM-dd", // 指定傳回結果的日期格式
"ranges": [
{
"from": "2019-09-01", // 指定日期範圍,可以使用date match
"to": "2019-09-30"
}
]
}
}
}
}
- Histogram:直方圖,以固定間隔的政策來分割資料
GET testindex/_search
{
"aggs": {
"salary_hist": {
"histogram": { // 關鍵詞
"field": "salary",
"interval": 5000, // 指定間隔大小
"extended_bounds": { // 指定資料範圍
"min": 0,
"max": 50000
}
}
}
}
}
- Date Histogram:針對日期的直方圖或者柱狀圖,是時序資料分析中的常用聚合分析類型
GET testindex/_search
{
"aggs": {
"by_year": {
"date_histogram": { // 關鍵詞
"field": "birth",
"interval": "year", // 指定間隔大小
"format": "yyyy"
}
}
}
}
四、Metric 聚合分析
主要分如下2類:
- 單值分析,隻輸出一個分析結果,常見的有min ,max ,avg ,sum , cardinality
- 多值分析,輸出多個分析結果,常見的有stats ,extended stats ,percentile , percentile rank ,top hits
1、cardinality
集合的勢,或者基數,是指不同數值的個數。可以類比成 SQL 中的 distinct count意思。分組求和,比如某列的數值有多個不同的值。
2、stats
傳回一系列數值類型的統計值,包含了min、max、avg、sum和count。一次做了多種分析。
3、extended_stats
顧名思義,是對stats的擴充,包含了更多的統計資料,如方差、标準差等。
4、percentiles與percentile_ranks
百分位數統計。如下:
// 比如:第一行的意思是18歲以下的人數占1.0%
{
"took": 55,
......
"aggregations": {
"per_age": {
"1.0": 18,
"5.0": 25,
"25.0": 29,
"50.0": 31,
"75.0": 40,
"95.0": 60,
"99.0": 80
}
}
}
// 指定展示的百分位數(隻展示95%,99%,99.9%的資料)
GET testindex/_search
{
"aggs": {
"per_salary": {
"percentiles": {
"field": "salary",
"percents": [
95,
99,
99.9
]
}
}
}
}
5、top_hits
一般用于分桶聚合後,擷取該桶内最比對的頂部文檔清單,即詳情資料。如下:
GET testindex/_search
{
"aggs": {
"group_jobs": {
"terms": { // 分桶聚合
"field": "job.keyword"
},
"aggs": {
"top_employee": {
"top_hits": { // 關鍵詞
"size": 10,
"sort": [
{
"age": {
"order": "desc"
}
}
]
}
}
}
}
}
}
五、Bucket + Metric 聚合分析
Bucket 聚合分析允許通過添加子分析來進一步分析,該子分析可以是 Bucket 也可以是 Metric。
六、pipeline 聚合分析
pipeline的分析結果會輸出到原結果中,根據輸出位置的不同,可以分為2類。
1、parent 結果内嵌到現有的聚合分析結果中:
- Derivative:計算Bucket 值的導數。
- Moving Average:計算Bucket值的移動平均值。
- Cumulative Sum:計算Bucket值的累計加和。
2、Sibling 結果與現有聚合分析結果同級
- Max/Min/Avg/Sum Bucket
- Stats/Extended Stats Bucket
- Percentiles Bucket
七、聚合分析作用範圍
es聚合分析預設作用範圍是 query 的結果集,可以通過 filter、post_filter、global 改變其作用範圍。
filter
它是為某個聚合分析設定過濾條件的,進而在不更改整體query 語句的情況下修改作用範圍。
post_filter
作用于文檔過濾,但在聚合分析後生效,過濾輸出的結果。
global
無視query的過濾條件,基于全部文檔進行分析。比如你在query裡面進行了文檔過濾,但是global還是會基于全部文檔去分析。
八、排序
可以使用自帶的關鍵資料進行排序,比如:
- _count 文檔數
- _key 按照key值排序
GET testindex/_search
{
"aggs": {
"group_jobs": {
"terms": { // 分桶聚合
"field": "job.keyword",
"order": { // 排序
"_count": "asc"
}
}
}
}
}
九、聚合分析精度問題
max、min這種是精确地,但是 terms 是不一定精确地。可以通過參數來優化它。
- 設定shard 數為1,消除資料分散的問題,但缺點比較明顯,無法承載大資料量。
- 合理設定 shard_size 大小,即每次從shard 上額外多擷取資料,以提升精确度。
terms 聚合傳回結果中有如下2個統計值:
- doc_count_error_upper_bound 被遺漏的 term 可能的最大值
- sum_other_doc_count 傳回結果 bucket 的term外,其他term的文檔總數
注:shard_size大小的設定方法
設定show_term_doc_count_error=true可以檢視每個bucket誤算的最大值。當其傳回結果的doc_count_error_upper_bound=0,則說明計算是準确的,不存在誤差。
GET testindex/_search
{
"aggs": {
"jobs": {
"terms": {
"field": "job.keyword",
"show_term_doc_count_error": true
}
}
}
}
shard_size預設大小如下:shard_size=size * 1.5 + 10
通過調整shard_size 的大小降低doc_count_error_upper_bound來提升準确度(随之而來的影響是增大了整體的計算量,進而降低了響應時間)
GET testindex/_search
{
"aggs": {
"jobs": {
"terms": {
"field": "job.keyword",
"shard_size": 10, // 關鍵詞
"show_term_doc_count_error": true
}
}
}
}
十、熱詞分析(對熱詞内容先分詞再聚合)
第一步,設定mapping(指定分詞器和開啟fielddata,因為你想要分詞,是以type毫無疑問是text)
PUT test
{
"mappings": {
"doc": {
"properties": {
"hello": {
"type": "text",
"analyzer": "ik_max_word",
"fielddata": true
}
}
}
}
}
第二步,插入測試資料
PUT test/doc/1
{
"hello": "北京加油"
}
第三步,聚合查詢
GET test/_search
{
"query": {
"match_all": {}
},
"aggs": {
"NAME": {
"terms": {
"field": "hello",
"size": 10
}
}
}
}
結果如下:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "test123",
"_type": "doc",
"_id": "1",
"_score": 1,
"_source": {
"hello": "北京加油"
}
}
]
},
"aggregations": {
"NAME": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "北京",
"doc_count": 1
},
{
"key": "加油",
"doc_count": 1
}
]
}
}
}