Elasticsearch(Es)聚合查詢(指標聚合、桶聚合)


Elasticsearch(Es)聚合查詢(指標聚合、桶聚合)


Elasticsearch 的聚合功能十分強大,可在數據上做復雜的分析統計。它提供的聚合分析功能有指標聚合(metrics aggregations)桶聚合(bucket aggregations)管道聚合(pipeline aggregations)矩陣聚合(matrix aggregations)四大類。

聚合的具體結構

所有的聚合,無論它們是什么類型,都遵從以下的規則。

  • 使用查詢中同樣的 JSON 請求來定義它們,而且你是使用鍵 aggregations 或者是 aggs 來進行標記。需要給每個聚合起一個名字,指定它的類型以及和該類型相關的選項。
  • 它們運行在查詢的結果之上。和查詢不匹配的文檔不會計算在內,除非你使用 global 聚集將不匹配的文檔囊括其中。
  • 可以進一步過濾查詢的結果,而不影響聚集。

以下是聚合的基本結構:

"aggregations" : { <!-- 最外層的聚合鍵,也可以縮寫為 aggs -->
    "<aggregation_name>" : { <!-- 聚合的自定義名字 -->
        "<aggregation_type>" : { <!-- 聚合的類型,指標相關的,如 max、min、avg、sum,桶相關的 terms、filter 等 -->
            <aggregation_body> <!-- 聚合體:對哪些字段進行聚合,可以取字段的值,也可以是腳本計算的結果 -->
        }
        [,"meta" : {  [<meta_data_body>] } ]? <!-- 元 -->
        [,"aggregations" : { [<sub_aggregation>]+ } ]? <!-- 在聚合里面在定義子聚合 -->
    }
    [,"<aggregation_name_2>" : { ... } ]* <!-- 聚合的自定義名字 2 -->
}
  • 在最上層有一個 aggregations 的鍵,可以縮寫為 aggs
  • 在下面一層,需要為聚合指定一個名字。可以在請求的返回中看到這個名字。在同一個請求中使用多個聚合時,這一點非常有用,它讓你可以很容易地理解每組結果的含義。
  • 最后,必須要指定聚合的類型。

關於聚合分析的值來源,可以取字段的值,也可以是腳本計算的結果

但是用腳本計算的結果時,需要注意腳本的性能和安全性;盡管多數聚集類型允許使用腳本,但是腳本使得聚集變得緩慢,因為腳本必須在每篇文檔上運行。為了避免腳本的運行,可以在索引階段進行計算。

此外,腳本也可以被人可能利用進行惡意代碼攻擊,盡量使用沙盒(sandbox)內的腳本語言。

示例

查詢所有球員的平均年齡是多少,並對球員的平均薪水加 188(也可以理解為每名球員加 188 后的平均薪水)。

POST /player/_search?size=0
{
  "aggs": {
    "avg_age": {
      "avg": {
        "field": "age"
      }
    },
    "avg_salary_188": {
      "avg": {
        "script": {
          "source": "doc.salary.value + 188"
        }
      }
    }
  }
}

指標聚合

指標聚合(又稱度量聚合)主要從不同文檔的分組中提取統計數據,或者,從來自其他聚合的文檔桶來提取統計數據。

這些統計數據通常來自數值型字段,如最小或者平均價格。用戶可以單獨獲取每項統計數據,或者也可以使用 stats 聚合來同時獲取它們。更高級的統計數據,如平方和或者是標准差,可以通過 extended stats 聚合來獲取。

Max Aggregation

Max Aggregation 用於最大值統計。例如,統計 sales 索引中價格最高的是哪本書,並且計算出對應的價格的 2 倍值,查詢語句如下:

GET /sales/_search?size=0
{
  "aggs" : {
    "max_price" : { 
      "max" : { 
        "field" : "price" 
      } 
    },
    "max_price_2" : { 
      "max" : { 
        "field" : "price",
        "script": {
          "source": "_value * 2.0"
        } 
      } 
    }
  }
}

指定的 field,在腳本中可以用 _value 取字段的值

聚合結果如下:

{
  ...
  "aggregations": {
    "max_price": {
      "value": 188.0
    },
    "max_price_2": {
      "value": 376.0
    }
  }
}

Min Aggregation

Min Aggregation 用於最小值統計。例如,統計 sales 索引中價格最低的是哪本書,查詢語句如下:

GET /sales/_search?size=0
{
  "aggs" : {
    "min_price" : { 
      "min" : { 
        "field" : "price" 
      } 
    }
  }
}

聚合結果如下:

{
  ...
  "aggregations": {
    "min_price": {
      "value": 18.0
    }
  }
}

Avg Aggregation

Avg Aggregation 用於計算平均值。例如,統計 exams 索引中考試的平均分數,如未存在分數,默認為 60 分,查詢語句如下:

GET /exams/_search?size=0
{
  "aggs" : {
    "avg_grade" : { 
      "avg" : { 
        "field" : "grade",
        "missing": 60
      } 
    }
  }
}

如果指定字段沒有值,可以通過 missing 指定默認值;若未指定默認值,缺失該字段值的文檔將被忽略(計算)

聚合結果如下:

{
  ...
  "aggregations": {
    "avg_grade": {
      "value": 78.0
    }
  }
}

除了常規的平均值聚合計算外,elasticsearch 還提供了加權平均值的聚合計算,詳情參見 Elasticsearch 指標聚合之 Weighted Avg Aggregation

Sum Aggregation

Sum Aggregation 用於計算總和。例如,統計 sales 索引中 type 字段中匹配 hat 的價格總和,查詢語句如下:

GET /exams/_search?size=0
{
  "query" : {
    "constant_score" : {
      "filter" : {
        "match" : { "type" : "hat" }
      }
    }
  },
  "aggs" : {
    "hat_prices" : { 
      "sum" : { "field" : "price" } 
    }
  }
}

聚合結果如下:

{
  ...
  "aggregations": {
    "hat_prices": {
      "value": 567.0
    }
  }
}

Value Count Aggregation

Value Count Aggregation 可按字段統計文檔數量。例如,統計 books 索引中包含 author 字段的文檔數量,查詢語句如下:

GET /books/_search?size=0
{
  "aggs" : {
    "doc_count" : { 
      "value_count" : { "field" : "author" } 
    }
  }
}

聚合結果如下:

{
  ...
  "aggregations": {
    "doc_count": {
      "value": 5
    }
  }
}

Cardinality Aggregation

Cardinality Aggregation 用於基數統計,其作用是先執行類似 SQL 中的 distinct 操作,去掉集合中的重復項,然后統計排重后的集合長度。例如,在 books 索引中對 language 字段進行 cardinality 操作可以統計出編程語言的種類數,查詢語句如下:

GET /books/_search?size=0
{
  "aggs" : {
    "all_lan" : { 
      "cardinality" : { "field" : "language" } 
    },
    "title_cnt" : { 
      "cardinality" : { "field" : "title.keyword" } 
    }
  }
}

假設 title 字段為文本類型(text),去重時需要指定 keyword,表示把 title 作為整體去重,即不分詞統計

聚合結果如下:

{
  ...
  "aggregations": {
    "all_lan": {
      "value": 8
    },
    "title_cnt": {
      "value": 18
    }
  }
}

Stats Aggregation

Stats Aggregation 用於基本統計,會一次返回 count、max、min、avg 和 sum 這 5 個指標。例如,在 exams 索引中對 grade 字段進行分數相關的基本統計,查詢語句如下:

GET /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
    }
  }
}

Extended Stats Aggregation

Extended Stats Aggregation 用於高級統計,和基本統計功能類似,但是會比基本統計多出以下幾個統計結果,sum_of_squares(平方和)、variance(方差)、std_deviation(標准差)、std_deviation_bounds(平均值加/減兩個標准差的區間)。在 exams 索引中對 grade 字段進行分數相關的高級統計,查詢語句如下:

GET /exams/_search?size=0
{
  "aggs" : {
    "grades_stats" : { 
      "extended_stats" : { "field" : "grade" } 
    }
  }
}

聚合結果如下:

{
  ...
  "aggregations": {
    "grades_stats": {
      "count": 2,
      "min": 50.0,
      "max": 100.0,
      "avg": 75.0,
      "sum": 150.0,
      "sum_of_squares": 12500.0,
      "variance": 625.0,
      "std_deviation": 25.0,
      "std_deviation_bounds": {
        "upper": 125.0,
        "lower": 25.0
      }
    }
  }
}

Percentiles Aggregation

Percentiles Aggregation 用於百分位統計。百分位數是一個統計學術語,如果將一組數據從大到小排序,並計算相應的累計百分位,某一百分位所對應數據的值就稱為這一百分位的百分位數。默認情況下,累計百分位為 [ 1, 5, 25, 50, 75, 95, 99 ]。以下例子給出了在 latency 索引中對 load_time 字段進行加載時間的百分位統計,查詢語句如下:

GET latency/_search
{
  "size": 0,
  "aggs" : {
    "load_time_outlier" : {
      "percentiles" : {
        "field" : "load_time" 
      }
    }
  }
}

需要注意的是,如上的 load_time 字段必須是數字類型

聚合結果如下:

{
  ...
  "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
      }
    }
  }
}

百分位的統計也可以指定 percents 參數指定百分位,如下:

GET latency/_search
{
  "size": 0,
  "aggs" : {
    "load_time_outlier" : {
      "percentiles" : {
        "field" : "load_time",
        "percents": [60, 80, 95]
      }
    }
  }
}

Percentiles Ranks Aggregation

Percentiles Ranks Aggregation 與 Percentiles Aggregation 統計恰恰相反,就是想看當前數值處在什么范圍內(百分位), 假如你查一下當前值 500 和 600 所處的百分位,發現是 90.01 和 100,那么說明有 90.01 % 的數值都在 500 以內,100 % 的數值在 600 以內。

GET latency/_search
{
  "size": 0,
    "aggs" : {
      "load_time_ranks" : {
        "percentile_ranks" : {
          "field" : "load_time", 
          "values" : [500, 600]
        }
      }
  }
}

同樣 load_time 字段必須是數字類型

返回結果大概類似如下:

{
  ...
  "aggregations": {
    "load_time_ranks": {
      "values" : {
        "500.0": 90.01,
        "600.0": 100.0
      }
    }
  }
}

可以設置 keyed 參數為 true,將對應的 values 作為桶 key 一起返回,默認是 false

GET latency/_search
{
  "size": 0,
  "aggs": {
    "load_time_ranks": {
      "percentile_ranks": {
        "field": "load_time",
        "values": [500, 600],
        "keyed": true
      }
    }
  }
}

返回結果如下:

{
  ...
  "aggregations": {
    "load_time_ranks": {
      "values": [
        {
          "key": 500.0,
          "value": 90.01
        },
        {
          "key": 600.0,
          "value": 100.0
        }
      ]
    }
  }
}

桶聚合

bucket 可以理解為一個桶,它會遍歷文檔中的內容,凡是符合某一要求的就放入一個桶中,分桶相當於 SQL 中的 group by。從另外一個角度,可以將指標聚合看成單桶聚合,即把所有文檔放到一個桶中,而桶聚合是多桶型聚合,它根據相應的條件進行分組。

桶聚合種類
種類 描述/場景
詞項聚合(Terms Aggregation) 用於分組聚合,讓用戶得知文檔中每個詞項的頻率,它返回每個詞項出現的次數。
差異詞項聚合(Significant Terms Aggregation) 它會返回某個詞項在整個索引中和在查詢結果中的詞頻差異,這有助於我們發現搜索場景中有意義的詞。
過濾器聚合(Filter Aggregation) 指定過濾器匹配的所有文檔到單個桶(bucket),通常這將用於將當前聚合上下文縮小到一組特定的文檔。
多過濾器聚合(Filters Aggregation) 指定多個過濾器匹配所有文檔到多個桶(bucket)。
范圍聚合(Range Aggregation) 范圍聚合,用於反映數據的分布情況。
日期范圍聚合(Date Range Aggregation) 專門用於日期類型的范圍聚合。
IP 范圍聚合(IP Range Aggregation) 用於對 IP 類型數據范圍聚合。
直方圖聚合(Histogram Aggregation) 可能是數值,或者日期型,和范圍聚集類似。
時間直方圖聚合(Date Histogram Aggregation) 時間直方圖聚合,常用於按照日期對文檔進行統計並繪制條形圖。
空值聚合(Missing Aggregation) 空值聚合,可以把文檔集中所有缺失字段的文檔分到一個桶中。
地理點范圍聚合(Geo Distance Aggregation) 用於對地理點(geo point)做范圍統計。

Terms Aggregation

Terms Aggregation 用於詞項的分組聚合。最為經典的用例是獲取 X 中最頻繁(top frequent)的項目,其中 X 是文檔中的某個字段,如用戶的名稱、標簽或分類。由於 terms 聚集統計的是每個詞條,而不是整個字段值,因此通常需要在一個非分析型的字段上運行這種聚集。原因是, 你期望“big data”作為詞組統計,而不是“big”單獨統計一次,“data”再單獨統計一次。

用戶可以使用 terms 聚集,從分析型字段(如內容)中抽取最為頻繁的詞條。還可以使用這種信息來生成一個單詞雲。

{
  "aggs": {
    "profit_terms": {
      "terms": { // terms 聚合 關鍵字
        "field": "profit",
        ......
      }
    }
  }
}

在 terms 分桶的基礎上,還可以對每個桶進行指標統計,也可以基於一些指標或字段值進行排序。示例如下:

{
  "aggs": {
    "item_terms": {
      "terms": {
        "field": "item_id",
        "size": 1000,
        "order":[{
          "gmv_stat": "desc"
        },{
          "gmv_180d": "desc"
        }]
      },
      "aggs": {
        "gmv_stat": {
          "sum": {
            "field": "gmv"
          }
        },
        "gmv_180d": {
          "sum": {
            "script": "doc['gmv_90d'].value*2"
          }
        }
      }
    }
  }
}

返回的結果如下:

{
  ...
  "aggregations": {
    "hospital_id_agg": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 260,
      "buckets": [
        {
          "key": 23388,
          "doc_count": 18,
          "gmv_stat": {
            "value": 176220
          },
          "gmv_180d": {
            "value": 89732
          }
        },
        {
          "key": 96117,
          "doc_count": 16,
          "gmv_stat": {
            "value": 129306
          },
          "gmv_180d": {
            "value": 56988
          }
        },
        ...
      ]
    }
  }
}

默認情況下返回按文檔計數從高到低的前 10 個分組,可以通過 size 參數指定返回的分組數。

Filter Aggregation

Filter Aggregation 是過濾器聚合,可以把符合過濾器中的條件的文檔分到一個桶中,即是單分組聚合。

{
  "aggs": {
    "age_terms": {
      "filter": {"match":{"gender":"F"}},
      "aggs": {
        "avg_age": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  }
}

Filters Aggregation

Filters Aggregation 是多過濾器聚合,可以把符合多個過濾條件的文檔分到不同的桶中,即每個分組關聯一個過濾條件,並收集所有滿足自身過濾條件的文檔。

{
  "size": 0,
  "aggs": {
    "messages": {
      "filters": {
        "filters": {
          "errors": { "match": { "body": "error" } },
          "warnings": { "match": { "body": "warning" } }
        }
      }
    }
  }
}

在這個例子里,我們分析日志信息。聚合會創建兩個關於日志數據的分組,一個收集包含錯誤信息的文檔,另一個收集包含告警信息的文檔。而且每個分組會按月份划分。

{
  ...
  "aggregations": {
    "messages": {
      "buckets": {
        "errors": {
          "doc_count": 1
        },
        "warnings": {
          "doc_count": 2
        }
      }
    }
  }
}

Range Aggregation

Range Aggregation 范圍聚合是一個基於多組值來源的聚合,可以讓用戶定義一系列范圍,每個范圍代表一個分組。在聚合執行的過程中,從每個文檔提取出來的值都會檢查每個分組的范圍,並且使相關的文檔落入分組中。注意,范圍聚合的每個范圍內包含 from 值但是排除 to 值。

{
  "aggs": {
    "age_range": {
      "range": {
        "field": "age",
          "ranges": [{
            "to": 25
          },
          {
            "from": 25,
            "to": 35
          },
          {
            "from": 35
          }]
        },
        "aggs": {
          "bmax": {
            "max": {
              "field": "balance"
            }
          }
        }
      }
    }
  }
}

返回結果如下:

{
  ...
  "aggregations": {
    "age_range": {
      "buckets": [{
        "key": "*-25.0",
        "to": 25,
        "doc_count": 225,
        "bmax": {
          "value": 49587
        }
      },
      {
        "key": "25.0-35.0",
        "from": 25,
        "to": 35,
        "doc_count": 485,
        "bmax": {
          "value": 49795
        }
      },
      {
        "key": "35.0-*",
        "from": 35,
        "doc_count": 290,
        "bmax": {
          "value": 49989
        }
      }]
    }
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM