Elasticsearch(5.0)中的Aggregation查詢大概分一下幾類
具體查看:https://www.elastic.co/guide/en/elasticsearch/reference/5.0/search-aggregations.html
下面將通過java api操作來總結其使用方法:
操作之前,我們首先建一個employee索引,employee索引類型包括8個字段:編號(id), 姓名(ename),性別(sex),年齡(age),籍貫(birthplace),部門名稱(deptid),職位(job),工資(salary)。
生成的mapping如下:
mapping創建成功后,我隨機插入了100條數據
一: Metrics Aggregations
1:對單個字段group by
例如要計算每個部門的男性員工數,如果使用SQL語句,應表達如下:
select
deptid
, count(*) as emp_count from employee group by deptid where sex=0
es的java代碼如下:
public static void groupByTest(TransportClient client) { SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX_NAME).setTypes(MAPPING_TYPE); TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("emp_count").field("deptid"); requestBuilder.setQuery(QueryBuilders.termQuery("sex", 0)).addAggregation(termsAggregationBuilder); SearchResponse response = requestBuilder.execute().actionGet(); Terms aggregation = response.getAggregations().get("emp_count"); for (Terms.Bucket bucket : aggregation.getBuckets()) { System.out.println("部門編號=" + bucket.getKey() + ";員工數=" + bucket.getDocCount()); } }
輸入結果:
部門編號=8;員工數=31
部門編號=5;員工數=25
部門編號=6;員工數=22
部門編號=7;員工數=22
2:group by多個field
例如要計算每個球隊每個位置的球員數,如果使用SQL語句,應表達如下:
select deptid, birthplace, count(*) as emp_count from employee group by deptid, birthplace
對應的java代碼如下:
public static void groupByMutilFieldTest(TransportClient client) { SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX_NAME).setTypes(MAPPING_TYPE); TermsAggregationBuilder aggregationBuilder1 = AggregationBuilders.terms("emp_count").field("deptid"); TermsAggregationBuilder aAggregationBuilder2 = AggregationBuilders.terms("region_count").field("birthplace"); requestBuilder.addAggregation(aggregationBuilder1.subAggregation(aAggregationBuilder2)); SearchResponse response = requestBuilder.execute().actionGet(); Terms terms1 = response.getAggregations().get("emp_count"); Terms terms2; for (Terms.Bucket bucket : terms1.getBuckets()) { System.out.println("部門編號=" + bucket.getKey()); terms2 = bucket.getAggregations().get("region_count"); for (Terms.Bucket bucket2 : terms2.getBuckets()) { System.out.println("籍貫=" + bucket2.getKey() + ";員工數=" + bucket2.getDocCount()); } } }
輸入的結果:
部門編號=8
籍貫=廣東佛山;員工數=9
籍貫=湖北武漢;員工數=8
籍貫=湖南長沙;員工數=5
籍貫=廣東深圳;員工數=4
籍貫=廣東廣州;員工數=3
籍貫=湖南岳陽;員工數=2
部門編號=5
籍貫=湖北武漢;員工數=7
籍貫=廣東佛山;員工數=4
籍貫=廣東廣州;員工數=4
籍貫=廣東深圳;員工數=4
籍貫=湖南岳陽;員工數=3
籍貫=湖南長沙;員工數=3
部門編號=6
籍貫=廣東廣州;員工數=6
籍貫=廣東佛山;員工數=4
籍貫=廣東深圳;員工數=4
籍貫=湖南岳陽;員工數=4
籍貫=湖北武漢;員工數=2
籍貫=湖南長沙;員工數=2
部門編號=7
籍貫=廣東廣州;員工數=6
籍貫=湖南岳陽;員工數=6
籍貫=廣東深圳;員工數=4
籍貫=湖北武漢;員工數=3
籍貫=廣東佛山;員工數=2
籍貫=湖南長沙;員工數=1
3:max/min/sum/avg
例如 計算每個部門最高的工資,如果使用SQL語句,應表達如下:
select deptid, max(salary) as max_salary from employee group by deptid
對應的java代碼如下:
public static void maxTest(TransportClient client) { SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX_NAME).setTypes(MAPPING_TYPE); TermsAggregationBuilder aggregationBuilder1 = AggregationBuilders.terms("deptid").field("deptid"); MaxAggregationBuilder aggregationBuilder2 = AggregationBuilders.max("maxsalary").field("salary"); requestBuilder.addAggregation(aggregationBuilder1.subAggregation(aggregationBuilder2)); SearchResponse response = requestBuilder.execute().actionGet(); Terms aggregation = response.getAggregations().get("deptid"); Max terms2 = null; for (Terms.Bucket bucket : aggregation.getBuckets()) { terms2 = bucket.getAggregations().get("maxsalary"); //class org.elasticsearch.search.aggregations.metrics.max.InternalMax System.out.println("部門編號=" + bucket.getKey() + ";最高工資=" + terms2.getValue()); } }
輸出結果:
部門編號=8;最高工資=8000.0
部門編號=5;最高工資=8000.0
部門編號=6;最高工資=8000.0
部門編號=7;最高工資=8000.0
4:對多個field求max/min/sum/avg
例如要計算每個部門的平均年齡,同時又要計算總薪資,最后按平均年齡升序排序,如果使用SQL語句,應表達如下:
select deptid, avg(age) as avg_age, sum(salary) as max_salary from employee group by deptid order by avg_age asc
對應的java代碼如下:
public static void methodTest1(TransportClient client) { SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX_NAME).setTypes(MAPPING_TYPE); TermsAggregationBuilder aggregationBuilder1 = AggregationBuilders.terms("deptid").field("deptid") // .order(Order.aggregation("avg_age", true)); //按平均年齡升序排序,
AggregationBuilder aggregationBuilder2 = AggregationBuilders.avg("avg_age").field("age"); AggregationBuilder aggregationBuilder3 = AggregationBuilders.sum("sum_salary").field("salary"); requestBuilder.addAggregation(aggregationBuilder1.subAggregation(aggregationBuilder2).subAggregation(aggregationBuilder3)); SearchResponse response = requestBuilder.execute().actionGet(); Terms aggregation = response.getAggregations().get("deptid"); Avg terms2 = null; Sum term3 = null; for (Terms.Bucket bucket : aggregation.getBuckets()) { terms2 = bucket.getAggregations().get("avg_age"); // org.elasticsearch.search.aggregations.metrics.avg.InternalAvg
term3 = bucket.getAggregations().get("sum_salary"); // org.elasticsearch.search.aggregations.metrics.sum.InternalSum
System.out.println("部門編號=" + bucket.getKey() + ";平均年齡=" + terms2.getValue() + ";總工資=" + term3.getValue()); } }
輸入結果:
部門編號=7;平均年齡=31.954545454545453;總工資=129000.0
部門編號=5;平均年齡=33.36;總工資=121000.0
部門編號=8;平均年齡=33.54838709677419;總工資=171000.0
部門編號=6;平均年齡=33.59090909090909;總工資=121000.0
總結
從實現上來講,SearchRequestBuilder在內部保持了一個私有的 SearchSourceBuilder實例, SearchSourceBuilder內部包含一個List<AbstractAggregationBuilder>,
每次調用addAggregation時會調用 SearchSourceBuilder實例,添加一個AggregationBuilder。
同樣的,TermsAggregationBuilder也在內部保持了一個List<AbstractAggregationBuilder>,調用addAggregation方法(來自父類addAggregation)時會添加一個AggregationBuilder。
其他例子,補充中。。。