ElasticSearch 聚合分析
阿新 • • 發佈:2021-02-24
> **公號:碼農充電站pro**
> **主頁:**
ES 中的[聚合分析](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations.html)(Aggregations)是對資料的統計分析功能,它的優點是**實時性較高**,相比於 Hadoop 速度更快。
### 1,聚合的分類
ES 中的聚合分析主要有以下 3 大類,每一類都提供了多種統計方法:
- [Metrics](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics.html):對文件欄位進行統計分析(數學運算),多數 **Metrics** 的輸出是單個值,部分 **Metrics** 的輸出是多個值。
- [Sum](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-sum-aggregation.html):求和
- [Max](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-max-aggregation.html):求最大值
- [Min](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-min-aggregation.html):求最小值
- [Avg](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-avg-aggregation.html):求平均值
- 等
- [Bucket](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket.html):一些滿足特定條件的文件集合(對文件進行**分組**)。
- [Terms](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-terms-aggregation.html)
- [Range](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-range-aggregation.html)
- 等
- [Pipeline](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline.html):對其它的聚合結果進行**再聚合**。
- [Avg bucket](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline-avg-bucket-aggregation.html):求平均值
- [Max bucket](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline-max-bucket-aggregation.html):求最大值
- [Min bucket](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline-min-bucket-aggregation.html):求最小值
- [Sum bucket](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline-sum-bucket-aggregation.html):求和
- [Stats bucket](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline-stats-bucket-aggregation.html):綜合統計
- [Percentiles bucket](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline-percentiles-bucket-aggregation.html):百分位數統計
- [Cumulative sum](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-pipeline-cumulative-sum-aggregation.html):累計求和
- 等
一般使用聚合分析時,通常將 **size** 設定為 0,表示不需要返回查詢結果,只需要返回聚合結果。
一個示例:
```shell
# 多個 Metric 聚合,找到最低最高和平均工資
POST index_name/_search
{
"size": 0, # size 為 0
"aggs": {
"max_salary": { # 自定義聚合名稱
"max": { # 聚合型別
"field": "salary" # 聚合欄位
}
},
"min_salary": { # 自定義聚合名稱
"min": { # 聚合型別
"field": "salary" # 聚合欄位
}
},
"avg_salary": { # 自定義聚合名稱
"avg": { # 聚合型別
"field": "salary" # 聚合欄位
}
}
}
}
```
### 2,Metrics 聚合
Metrics 聚合可以分為單值分析和多值分析:
- 單值分析:分析結果是單個值
- max
- min
- avg
- sum
- [cardinality](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-cardinality-aggregation.html):類似 distinct count
- 注意 cardinality 對 keyword 型別資料和 text 型別資料的區別
- keyword 型別不會進行分詞處理,而 text 型別會進行分詞處理
- 等
- 多值分析:分析結果是多個值
- [stats](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-stats-aggregation.html)
- [extended stats](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-extendedstats-aggregation.html)
- [string stats](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-string-stats-aggregation.html)
- [percentiles](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-percentile-aggregation.html)
- [percentile ranks](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-percentile-rank-aggregation.html)
- [top hits](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-top-hits-aggregation.html):根據一定的規則排序,選 top N
- 等
#### 2.1,示例
示例,一個員工表定義:
```shell
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"
}
}
}
}
```
插入一些測試資料:
```shell
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}
{ "index" : { "_id" : "11" } }
{ "name" : "Jenny","age":36,"job":"Java Programmer","gender":"female","salary":38000 }
{ "index" : { "_id" : "12" } }
{ "name" : "Mcdonald","age":31,"job":"Java Programmer","gender":"male","salary": 32000}
{ "index" : { "_id" : "13" } }
{ "name" : "Jonthna","age":30,"job":"Java Programmer","gender":"female","salary":30000 }
{ "index" : { "_id" : "14" } }
{ "name" : "Marshall","age":32,"job":"Javascript Programmer","gender":"male","salary": 25000}
{ "index" : { "_id" : "15" } }
{ "name" : "King","age":33,"job":"Java Programmer","gender":"male","salary":28000 }
{ "index" : { "_id" : "16" } }
{ "name" : "Mccarthy","age":21,"job":"Javascript Programmer","gender":"male","salary": 16000}
{ "index" : { "_id" : "17" } }
{ "name" : "Goodwin","age":25,"job":"Javascript Programmer","gender":"male","salary": 16000}
{ "index" : { "_id" : "18" } }
{ "name" : "Catherine","age":29,"job":"Javascript Programmer","gender":"female","salary": 20000}
{ "index" : { "_id" : "19" } }
{ "name" : "Boone","age":30,"job":"DBA","gender":"male","salary": 30000}
{ "index" : { "_id" : "20" } }
{ "name" : "Kathy","age":29,"job":"DBA","gender":"female","salary": 20000}
```
**min** 聚合分析:
```shell
# Metric 聚合,找到最低的工資
POST employees/_search
{
"size": 0,
"aggs": {
"min_salary": {
"min": { # 聚合型別,求最小值
"field":"salary"
}
}
}
}
# 返回結果
"hits": {
"total": {
"value": 20, # 一共統計了多少條資料
"relation": "eq"
},
"max_score": null,
"hits": [...] # 因為 size 為 0
},
"aggregations": {
"min_salary": { # 自定義的聚合名稱
"value": 9000,
}
}
```
**stats** 聚合分析:
```shell
# 輸出多值
POST employees/_search
{
"size": 0,
"aggs": {
"stats_salary": {
"stats": { # stats 聚合
"field":"salary"
}
}
}
}
# 返回多值結果
"aggregations": {
"stats_salary": { # 自定義的聚合名稱
"count": 20,
"min": 9000,
"max": 50000,
"avg": 24700,
"sum": 494000
}
}
```
#### 2.2,top_hits 示例
```shell
# 指定 size,不同崗位中,年紀最大的3個員工的資訊
POST employees/_search
{
"size": 0,
"aggs":{
"old_employee":{ # 聚合名稱
"top_hits":{ # top_hits 分桶
"size":3,
"sort":[ # 根據 age 倒序排序,選前 3 個
{"age":{"order":"desc"}}
]
}
}
}
}
```
### 3,Bucket 聚合
Bucket 聚合按照一定的規則,將文件分配到不同的**桶**中,達到分類的目的。
Bucket 聚合**支援巢狀**,也就是在桶裡再次分桶。
Bucket 聚合演算法:
- [Terms](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-terms-aggregation.html):根據關鍵字(字串)分桶。**text** 型別的欄位需要開啟 **fielddata** 配置。
- 注意 keyword 型別不會做分詞處理,text 型別會做分詞處理。
- 另外 **size 引數**可以控制**桶的數量**。
- [Range](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-range-aggregation.html):按照範圍進行分桶,主要針對**數字型別的資料**。
- [Date range](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-daterange-aggregation.html)
- [Histogram](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-histogram-aggregation.html):直方圖分桶,指定一個間隔值,來進行分桶。
- [Date histogram](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-datehistogram-aggregation.html)
- 等
#### 3.1,Terms 示例
示例:
```shell
# 對 keword 進行聚合
POST employees/_search
{
"size": 0, # size 為 0
"aggs": {
"jobs": { # 自定義聚合名稱
"terms": { # terms 聚合
"field":"job.keyword" # job 欄位的 keyword 子欄位
}
}
}
}
# 返回值結構示例
"aggregations": {
"genres": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [ # 很多桶,這是一個數組
{
"key": "electronic",
"doc_count": 6
},
{
"key": "rock",
"doc_count": 3
},
{
"key": "jazz",
"doc_count": 2
}
]
}
}
```
對 Text 欄位進行 terms 聚合查詢會出錯,示例:
```shell
# 對 Text 欄位進行 terms 聚合查詢
POST employees/_search
{
"size": 0,
"aggs": {
"jobs": {
"terms": {
"field":"job" # job 是 text 型別
}
}
}
}
# 對 Text 欄位開啟 fielddata,以支援 terms aggregation
PUT employees/_mapping
{
"properties" : {
"job":{
"type": "text",
"fielddata": true # 開啟 fielddata
}
}
}
```
#### 3.2,Terms 效能優化
當某個欄位的**寫入和 Terms 聚合**比較頻繁的時候,可用通過開啟 [eager_global_ordinals](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/tune-for-search-speed.html#_warm_up_global_ordinals) 配置來對 Terms 操作進行優化。
示例:
```shell
PUT index_name
{
"mappings": {
"properties": {
"foo": { # 欄位名稱
"type": "keyword",
"eager_global_ordinals": true # 開啟
}
}
}
}
```
#### 3.3,巢狀聚合示例
Bucket 聚合支援新增**子聚合**來進一步分析,子聚合可以是一個 **Metrics** 或者 **Bucket**。
示例 1:
```shell
# 指定 size,不同崗位中,年紀最大的3個員工的資訊
POST employees/_search
{
"size": 0,
"aggs": {
"jobs": {
"terms": { # 先做了一個 terms 分桶
"field":"job.keyword"
},
"aggs":{ # 巢狀一個聚合,稱為子聚合,
"old_employee":{ # 聚合名稱
"top_hits":{ # top_hits 分桶
"size":3,
"sort":[ # 根據 age 倒序排序,選前 3 個
{"age":{"order":"desc"}}
]
}
}
}
}
}
}
```
示例 2 :
```shell
POST employees/_search
{
"size": 0,
"aggs": {
"Job_salary_stats": {
"terms": { # 先做了一個 terms 分桶
"field": "job.keyword"
},
"aggs": {
"salary": {
"stats": { # 子聚合是一個 stats
"field": "salary"
}
}
}
}
}
}
# 多次巢狀
POST employees/_search
{
"size": 0,
"aggs": { # 第 1 層
"Job_gender_stats": {
"terms": {
"field": "job.keyword" # 先根據崗位分桶
},
"aggs": { # 第 2 層
"gender_stats": {
"terms": {
"field": "gender" # 再根據性別分桶
},
"aggs": { # 第 3 層
"salary_stats": {
"stats": { # 最後根據工資統計 stats
"field": "salary"
}
}
}
}
}
}
}
}
```
#### 3.4,Range 示例
對員工的工資進行區間聚合:
```shell
# Salary Ranges 分桶,可以自己定義 key
POST employees/_search
{
"size": 0,
"aggs": {
"salary_range": { # 自定義聚合名稱
"range": { # range 聚合
"field":"salary", # 聚合的欄位
"ranges":[ # range 聚合規則/條件
{
"to":10000 # salary < 10000
},
{
"from":10000, # 10000 < salary < 20000
"to":20000
},
{ # 如果沒有定義 key,ES 會自動生成
"key":"可以使用 key 自定義名稱",
"from":20000 # salary > 20000
}
]
}
}
}
}
```
#### 3.5,Histogram 示例
示例,工資0到10萬,以 **5000一個區間**進行分桶:
```shell
# Salary Histogram
POST employees/_search
{
"size": 0,
"aggs": {
"salary_histrogram": { # 自定義聚合名稱
"histogram": { # histogram 聚合
"field":"salary", # 聚合的欄位
"interval":5000, # 區間值
"extended_bounds":{ # 範圍
"min":0,
"max":100000
}
}
}
}
}
```
### 4,Pipeline 聚合
Pipeline 聚合用於對其它聚合的結果進行再聚合。
根據 **Pipeline 聚合**與**原聚合**的位置區別,分為兩類:
- **Pipeline 聚合**與**原聚合**同級,稱為 **Sibling 聚合**
- `Max_bucket`,`Min_bucket`,`Avg_bucket`,`Sum_bucket`
- `Stats_bucket`,`Extended-Status_bucket`
- `Percentiles_bucket`
- **Pipeline 聚合**內嵌在**原聚合**之內,稱為 **Parent 聚合**
- `Derivative`:求導
- `Cumulative-sum`:累計求和
- `Moving-function`:滑動視窗
#### 4.1,Sibling 聚合示例
示例:
```shell
# 平均工資最低的工作型別
POST employees/_search
{
"size": 0,
"aggs": {
"jobs": { # 自定義聚合名稱
"terms": {
"field": "job.keyword", # 先對崗位型別進行分桶
"size": 10
},
"aggs": {
"avg_salary": {
"avg": {
"field": "salary" # 再計算每種工資崗位的平價值
}
}
}
},
"min_salary_by_job":{ # 自定義聚合名稱
"min_bucket": { # pipeline 聚合
"buckets_path": "jobs>avg_salary"
} # 含義是:對 jobs 中的 avg_salary 進行一個 min_bucket 聚合
}
}
}
```
#### 4.2,Parent 聚合示例
示例:
```shell
# 示例 1
POST employees/_search
{
"size": 0,
"aggs": {
"age": { # 自定義聚合名稱
"histogram": {
"field": "age",
"min_doc_count": 1,
"interval": 1
},
"aggs": {
"avg_salary": { # 自定義聚合名稱
"avg": {
"field": "salary"
}
}, # 自定義聚合名稱
"derivative_avg_salary":{ # 注意 derivative 聚合的位置,與 avg_salary 同級
"derivative": { # 而不是與 age 同級
"buckets_path": "avg_salary" # 注意這裡不再有箭頭 >
}
}
}
}
}
}
# 示例 2
POST employees/_search
{
"size": 0,
"aggs": {
"age": {
"histogram": {
"field": "age",
"min_doc_count": 1,
"interval": 1
},
"aggs": {
"avg_salary": {
"avg": {
"field": "salary"
}
},
"cumulative_salary":{
"cumulative_sum": { # 累計求和
"buckets_path": "avg_salary"
}
}
}
}
}
}
```
### 5,聚合的作用範圍
ES 聚合的預設作用範圍是 Query 的查詢結果,如果沒有寫 Query,那預設就是在索引的所有資料上做聚合。
比如:
```shell
POST employees/_search
{
"size": 0,
"query": { # 在 query 的結果之上做聚合
"range": {
"age": {"gte": 20}
}
},
"aggs": {
"jobs": {
"terms": {"field":"job.keyword"}
}
}
}
```
ES 支援通過以下方式來改變聚合的作用範圍:
- Query:ES 聚合的預設作用範圍。
- **一般設定 size 為 0**。
- 如果沒有寫 Query,那預設就是在索引的所有資料上做聚合。
- Filter:寫在某個聚合的內部,只控制某個聚合的作用範圍。
- **一般設定 size 為 0**。
- Post Filter:對聚合沒有影響,只是對聚合的結果進行再過濾。
- **不再設定 size 為 0**。
- **使用場景**:獲取聚合資訊,並獲取符合條件的文件。
- Global:會覆蓋掉 Query 的影響。
#### 5.1,Filter 示例
示例:
```shell
POST employees/_search
{
"size": 0,
"aggs": {
"older_person": { # 自定義聚合名稱
"filter":{ # 通過 filter 改變聚合的作用範圍
"range":{
"age":{"from":35}
}
}, # end older_person
"aggs":{ # 在 filter 的結果之上做聚合
"jobs":{ # 自定義聚合名稱
"terms": {"field":"job.keyword"}
}
}
}, # end older_person
"all_jobs": { # 又一個聚合,沒有 filter
"terms": {"field":"job.keyword"}
}
}
}
```
#### 5.2,Post Filter 示例
示例:
```shell
POST employees/_search
{
"aggs": {
"jobs": { # 自定義聚合名稱
"terms": {"field": "job.keyword"}
}
}, # end aggs
"post_filter": { # 一個 post_filter,對聚合的結果進行過濾
"match": {
"job.keyword": "Dev Manager"
}
}
}
```
#### 5.3,Global 示例
```shell
POST employees/_search
{
"size": 0,
"query": { # 一個 query
"range": {
"age": {"gte": 40}
}
},
"aggs": {
"jobs": { # 一個聚合
"terms": {"field":"job.keyword"}
},
"all":{ # 又一個聚合,名稱為 all
"global":{}, # 這裡的 global 會覆蓋掉上面的 query,使得聚合 all 的作用範圍不受 query 的影響
"aggs":{ # 子聚合
"salary_avg":{ # 自定義聚合名稱
"avg":{"field":"salary"}
}
}
}
}
}
```
### 6,聚合中的排序
#### 6.1,基於 count 的排序
聚合中的排序使用 **order** 欄位,預設按照 **_count** 和 **_key** 進行排序。
- `_count`:表示按照文件數排序,如果不指定 **_count**,預設按照**降序**進行排序。
- `_key`:表示關鍵字(字串值),如果文件數相同,再按照 **key** 進行排序。
示例 1:
```shell
# 使用 count 和 key
POST employees/_search
{
"size": 0,
"query": {
"range": {
"age": {"gte": 20}
}
},
"aggs": {
"jobs": { # 自定義聚合名稱
"terms": { # terms 聚合
"field":"job.keyword",
"order":[ # order 排序
{"_count":"asc"}, # 先安裝文件數排序
{"_key":"desc"} # 如果文件數相同,再按照 key 排序
]
}
}
}
}
```
#### 6.2,基於子聚合的排序
也可以基於子聚合排序。
示例 2:
```shell
# 先對工作種類進行分桶
# 再以工作種類的平均工資進行排序
POST employees/_search
{
"size": 0,
"aggs": {
"jobs": { # 自定義聚合名稱
"terms": {
"field":"job.keyword",
"order":[ # 基於子聚合的排序
{"avg_salary":"desc"}
]
}, # end terms
"aggs": { # 子聚合
"avg_salary": { # 子聚合名稱
"avg": {"field":"salary"}
}
}
} # end jobs
}
}
```
如果子聚合是**多值輸出**,也可以基於 `子聚合名.屬性` 來進行排序,如下:
```shell
POST employees/_search
{
"size": 0,
"aggs": {
"jobs": {
"terms": {
"field":"job.keyword",
"order":[ # 基於子聚合的屬性排序
{"stats_salary.min":"desc"}
]
}, # end terms
"aggs": {
"stats_salary": { # 子聚合是多值輸出
"stats": {"field":"salary"}
}
}
} # end jobs
}
}
```
### 7,聚合分析的原理及精準度
下面介紹聚合分析的原理及精準度的問題。
#### 7.1,分散式系統的三個概念
分散式系統中有三個概念:
- 資料量
- 精準度
- 實時性
對於分散式系統(資料分佈在**不同的分片**上),這三個指標不能同時具備,**同時只能滿足其中的 2 個條件**:
- **Hadoop 離線計算**:可以同時滿足**大資料量和精準度**。
- **近似計算**:可以同時滿足**大資料量和實時性**。
- **有限資料計算**:可以同時滿足**精準度和實時性**。
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210122165649712.png)
ES 屬於**近似計算**,具備了**資料量**和**實時性**的特點,失去了**精準度**。
#### 7.2,聚合分析的原理
ES 是一個分散式系統,資料分佈在不同的分片上。
因此,ES 在進行聚合分析時,會先在每個**主分片**上做聚合,然後再將每個主分片上的聚合結果進行**彙總**,從而得到最終的聚合結果。
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210122180646970.png)
#### 7.3,聚合分析的精準度
分散式聚合的原理,會天生帶來精準度的問題,但並不是所有的聚合分析都有精準度問題:
- 比如 [Min 聚合](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-metrics-min-aggregation.html) 就不會有精準度問題。
- 因為**求總的最小值**,與**先在所有主分片求最小值,再彙總每個主分片的最小值**,它們最終的結果是一樣的。
- 比如 [Terms 聚合](https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations-bucket-terms-aggregation.html) 就有精準度問題。
下面來看下 **Terms** 聚合存在的問題,下圖中的:
- A(6) 表示 A 類的文件數有 6 個。
- B(4) 表示 B 類的文件數有 4 個。
- C(4) 表示 C 類的文件數有 4 個。
- D(3) 表示 D 類的文件數有 3 個。
下圖是 Terms 聚合流程:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210122182753831.png)
上圖中,在進行 Terms 聚合時(最終結果只要按照數量排序的前 3 個),需要分別在分片 **P0** 和 **P1**上做聚合,然後再將它們的聚合結果進行彙總。
正確的聚合結果應該是 `A(12),B(6),D(6)`,但是由於分片的原因,ES 計算出來的結果是 `A(12),B(6),C(4)`。這就是 **Terms** 聚合存在的精準度問題。
#### 7.4,show_term_doc_count_error 引數
開啟 [show_term_doc_count_error](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_per_bucket_document_count_error) 配置可以使得 terms 聚合的返回結果中有一個 `doc_count_error_upper_bound` 值(最小為0),通過該值可以瞭解精準程度;**該值越小,說明 Terms 的精準度越高**。
```shell
POST index_name/_search
{
"size": 0,
"aggs": {
"weather": { # 自定義聚合名稱
"terms": { # terms 聚合
"field":"OriginWeather",
"show_term_doc_count_error":true # 開啟
}
}
}
}
```
#### 7.5,如何提高 terms 精準度
提高 **terms** 聚合的精準度有兩種方式:
- 將主分片數設定為 1。
- 因為 terms 的不準確是由於分片導致的,如果將主分片數設定為 1,就不存在不準確的問題。
- 這種方式在資料量不是很大的時候,可以是使用。
- 將 [shard_size](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#_shard_size_3) 的值儘量調大(意味著從分片上額外獲取更多的資料,從而提升準確度)。
- **shard_size** 值變大後,會使得計算量變大,進而使得ES 的**整體效能變低,精準度變高**。
- 所以需要權衡 **shard_size** 值與精準度的平衡。
- **shard_size** 值的預設值是 【[**size**](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-size) * **1.5 + 10**】。
設定 **shard_size** 的語法:
```shell
POST my_flights/_search
{
"size": 0,
"aggs": {
"weather": {
"terms": {
"field":"OriginWeather",
"size":1,
"shard_size":1,
"show_term_doc_count_error":true
}
}
}
}
```
(本節完。)
---
**推薦閱讀:**
[ElasticSearch 查詢](https://www.cnblogs.com/codeshell/p/14389415.html)
[ElasticSearch URI 查詢](https://www.cnblogs.com/codeshell/p/14429420.html)
[ElasticSearch DSL 查詢](https://www.cnblogs.com/codeshell/p/14435120.html)
[ElasticSearch 文件及操作](https://www.cnblogs.com/codeshell/p/14429409.html)
[ElasticSearch 搜尋模板與建議](https://www.cnblogs.com/codeshell/p/14435151.html)
---
*歡迎關注作者公眾號,獲取更多技術乾貨。*
![碼農充電站pro](https://img-blog.csdnimg.cn/20200505082843773.png?#pic_