Elasticsearch Aggregation 筆記

Aggregation 概述

Aggregation 能夠和普通查詢結果並存,一個查詢結果中也容許包含多個不相關的Aggregation. 若是隻關心聚合結果而不關心查詢結果的話會把SearchSource的size設置爲0,能有效提升性能. html

Aggregation 類型

  1. Metrics:
    簡單聚合類型, 對於目標集和中的全部文檔計算聚合指標, 通常沒有嵌套的sub aggregations. 好比 平均值(avg) , 求和 (sum), 計數 (count), 基數 (cardinality). Cardinality對應distinct count node

  2. Bucketing:
    桶聚合類型, 在一系列的桶而不是全部文檔上計算聚合指標,每一個桶表示原始結果集合中符合某種條件的子集. 通常有嵌套的sub aggregations. 典型的如TermsAggregation, HistogramAggregation 算法

  3. Matrix:
    矩陣聚合, 多維度聚合, 即根據兩個或者多個聚合維度計算二維甚至多維聚合指標表格. 目前貌似只有一種MatrixStatAggregation. 而且目前不支持腳本(scripting) sql

  4. Pipeline:
    管道聚合, 在以前聚合結果的基礎上再次進行聚合計算, 每每和Bucketing Aggregation 結合起來使用. 舉列: 先求出過去30天天天的交易總金額 (Bucketing aggregation),再統計交易總金額大於10000的天數 (Pipeline aggregation).

Aggregation 結構

Aggregation request:
兩層結構:
Aggregation -> SubAggregation
Sub aggregation是在原來的Aggregation的計算結果中進一步作聚合計算elasticsearch

Aggregation response:
三層結構: (針對Bucketing aggregation) MultiBucketsAggregation -> Buckets -> Aggregations ide

Aggregation 屬性:
name: 和請求中的Aggregation的名字對應
buckets: 每一個Bucket對應Agggregation結果中每個可能的取值和相應的聚合結果. 函數

Bucket 屬性:
key: 對應的是聚合維度可能的取值, 具體的值和Aggregation的類型有關, 好比Term aggregation (按交易類型計算總金額), 那麼Bucket key值就是全部可能的交易類型 (credit/debit etc). 又好比DateHistogram aggregation (按天計算交易筆數), 那麼Bucket key值就是具體的日期.
docCount: 對應的是每一個桶中的文本數量.
value: 對應的是聚合指標的計算結果. 注意若是是多層Aggregation計算, 中間層的Aggregation value通常沒有值, 好比Term aggregation. 只有到底層具體計算指標的Aggregation纔有值.
aggregations: 對應請求中當前Aggregation的subAggregation的計算結果 (若是存在) 性能

SQL映射成Aggregation

SQL映射實現的前提: 只針對聚合計算,即sql select部分存在聚合函數類型的columnui

映射過程很難直接描述,上幾個例子方便你們理解,反正SQL的結構也無非就是SELECT/FROM/WHERE/GROUP BY/HAVING/ORDER BY. ORDER BY先不討論,通常聚合結果不太關心順序. FROM也很容易理解,就是索引的名字. htm

SQL組成部分對應的ES Builder:

Column 1 Column 2 Column 3
select column (聚合函數) MetricsAggregationBuilder 由 column對應聚合函數決定 (例如 MaxAggregationBuilder)
select column (group by 字段) Bucket key
where FiltersAggregationBuilder + FiltersAggregator.KeydFilter keyedFilter = FiltersAggregator.KeyedFilter("combineCondition", sub QueryBuilder) <br/> AggregationBuilders.filters("whereAggr", keyedFilter)
group by TermsAggregationBuilder AggregationBuilders.terms("aggregation name").field(fieldName)
having MetricsAggregationBuilder 由 having 條件聚合函數決定 (例如 MaxAggregationBuilder) + BucketSelectorPipelineAggregationBuilder PipelineAggregatorBuilders.bucketSelector(aggregationName, bucketPathMap, script)

經常使用的SQL運算符和聚合函數對應的ES Builder:

Sql element Aggregation Type Code to build
count(field) ValueCountAggregationBuilder AggregationBuilders.count(metricsName).field(fieldName)
count(distinct field) CardinalityAggregationBuilder AggregationBuilders.cardinality(metricsName).field(fieldName)
sum(field) SumAggregationBuilder AggregationBuilders.sum(metricsName).field(fieldName)
min(field) MinAggregationBuilder AggregationBuilders.min(metricsName).field(fieldName)
max(field) MaxAggregationBuilder AggregationBuilders.max(metricsName).field(fieldName)
avg(field) AvgAggregationBuilder AggregationBuilders.avg(metricsName).field(fieldName)
AND BoolQueryBuilder QueryBuilders.boolQuery().must().add(sub QueryBuilder)
OR BoolQueryBuilder QueryBuilders.boolQuery().should().add(sub QueryBuilder)
NOT BoolQueryBuilder QueryBuilders.boolQuery().mustNot().add(sub QueryBuilder)
= TermQueryBuilder QueryBuilders.termQuery(fieldName, value)
IN TermsQueryBuilder QueryBuilders.termsQuery(fieldName, values)
LIKE WildcardQueryBuilder QueryBuilders.wildcardQuery(fieldName, value)
> RangeQueryBuilder QueryBuilders.rangeQuery(fieldName).gt(value)
>= RangeQueryBuilder QueryBuilders.rangeQuery(fieldName).gte(value)
< RangeQueryBuilder QueryBuilders.rangeQuery(fieldName).lt(value)
<= RangeQueryBuilder QueryBuilders.rangeQuery(fieldName).lte(value)

1.select count(payerId) as payerCount from Payment group by country

Elasticsearch Aggregation 筆記
這裏須要注意的是payerId這個doc的屬性在實際構造的Aggregation query 中變成了 payerId.keyword,Elasticsearch 默認對於分詞的字段(text類型)不支持聚合,會報出 "Fielddata is disabled on text fields by default. Set fielddata=true"的錯誤. fielddata聚合是一個很是costly的運算,通常不建議使用. 好在Elasticsearch索引時默認會對payerId這個屬性生成兩個字段, payerId 是分詞的text類型, payerId.keyword是不分詞的keyword類型.

2.select max(payerId) from Payment group by accountId, country
Elasticsearch Aggregation 筆記
兩個group by 條件對應兩層term aggregation

3.select count(distinct payerId) as payerCount from Payment where country in ('CN', 'GE') group by accountId, country
Elasticsearch Aggregation 筆記
增長了where條件, 在頂層是一個FiltersAggregationBuilder. 其中分爲兩部分, 其中filters對應的是全部查詢條件構建的一個KeyedFilter, 其中又包含了多個子查詢條件. aggregations 對應的是groupBy條件和select部分的聚合函數

4.select count(distinct payerId) as payerCount from Payment where withinTime(createAt, 1, 'DAY') and name like '%SH%' group by accountId, country
Elasticsearch Aggregation 筆記
多個where條件, 用BoolQueryBuilder組合起來

5.select max(amount) as maxAmt, min(amount) as minAmt from Payment where amount > 1000.00 or amount <= 50.53 group by accountId, country having count(distinct beneficiaryId) > 3 and sum(amount) > 1530.20
Elasticsearch Aggregation 筆記
史上最複雜SQL產生! 這裏主要關注having部分的處理, 用到了Pipeline類型的BucketSelectorPipelineAggregationBuilder. 在最後一個GroupBy 條件對應的term aggregation下增長了兩類子節點: sub aggregations 除了包括select 部分的聚合函數還包括having條件對應的聚合函數. pipeline aggregations 包括having條件對應的 BucketSelectorPipelineAggregationBuilder. BucketSelectorPipelineAggregationBuilder 主要的屬性有: bucketsPathMap: 保存了path的名字和對應的聚合屬性的映射,script: 用腳本描述聚合條件,可是條件左側不直接使用屬性名而是path的名字替換
注意雖然從邏輯上來講having 條件是應用在以前計算出聚合的結果之上, 可是從ES Aggregation的結構來看, BucketSelectorPipelineAggregationBuilder和having 條件中對應聚合指標的Aggregation是兄弟關係而不是父子關係!
另外要注意script path 是對於兄弟節點(sibling node)一個相對路徑而不是從根節點Aggregation的絕對路徑,用的是聚合屬性的名稱而不是Aggregation自己的名稱. 而且要求根據路徑訪問到的Bucket必須是惟一的,由於BucketSelector只是根據條件判斷當前Bucket是否被選擇, 若是路徑返回多個Bucket則沒法應用這種Bool判斷.

6.select count(paymentId) from Payment group by timeRange(createdAt, '1D', 'yyyy/MM/dd')
Elasticsearch Aggregation 筆記
這裏用到一個自定義函數timeRage, 表示對於createAt這個屬性按天聚合,對應的ES aggregation類型爲DateHistogramAggregation

其餘注意事項

Bucket count

Distinct count: Elasticsearch 採用的是基於hyperLogLog的近似算法.

Reference

https://www.elastic.co/guide/en/elasticsearch/reference/current/fielddata.html

相關文章
相關標籤/搜索