Es聚合查询,对Object类型进行聚合分组查询
平常在es中查询都是精确查询,当某个值等于某个值的时候,例如
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termQuery("status", 3));
有时不知道字段的精确值,或是想要使用类似mysql中的group by 操作,就需要使用聚合查询,聚合查询又有求最大值、最小值、排序和分组等。
例如想要在person中查询age字段的最大值
GET /person/_search
{
"aggregations": {
"max_age": {
"max": {
"field": "age"
}
}
}
}
java代码
@Autowired
private RestHighLevelClient client;
@Test
public void maxQueryTest() throws IOException {
// 聚合查询条件
AggregationBuilder aggBuilder = AggregationBuilders.max("max_age").field("age");
SearchRequest searchRequest = new SearchRequest("person");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 将聚合查询条件构建到SearchSourceBuilder中
searchSourceBuilder.aggregation(aggBuilder);
System.out.println("searchSourceBuilder----->" + searchSourceBuilder);
searchRequest.source(searchSourceBuilder);
// 执行查询,获取SearchResponse
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(JSONObject.toJSON(response));
}
es中的聚合分组查询,类似于Mysql中的group by操作
http://localhost:9200/your_index/_search
{
"size": 0,
"aggs": {
"aggs_tag":{
"terms": {
"field": "id",
"order": {
"_count": "desc"
}
}
}
},
"query":{"term":{"batchId":"174268241231"}}
}
响应如下:
{
"took": 29,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 12,
"max_score": 0.0,
"hits": []
},
"aggregations": {
"aggs_tag": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 2,
"buckets": [
{
"key": 1645123213121232,
"doc_count": 2
},
{
"key": 1645123213121233,
"doc_count": 2
},
{
"key": 1645123213121234,
"doc_count": 1
},
{
"key": 1645123213121235,
"doc_count": 1
},
{
"key": 1645123213121241,
"doc_count": 1
}
]
}
}
}
但是es中的对象类型该如何查询呢,例如
{
"id":"1645123213121241",
"businessId":"17426824093424234",
"labels":{
"满意度回访":"1分",
"打分评价":"2分"
},
"batchType":"0",
"time":"2023-11-11 19:24:50",
}
这时要想对Labels中的某一字段进行分组查询,使用上述的请求 labels或者labels.满意度回访都不能得到结果
es中本身没有对象的概念,存储为object时,es会将对象平铺展开,即
labels.满意度回访:1分
labels.打分评价:2分
这时请求应为
{
"size": 0,
"aggs": {
"aggs_tag":{
"terms": {
"field": "labels.满意度回访.keyword",
"order": {
"_count": "desc"
}
}
}
},
"query":{"term":{"batchId":"17426824093424234"}}
}
得到响应
{
"took": 189,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 12,
"max_score": 0.0,
"hits": []
},
"aggregations": {
"aggs_tag": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "1分",
"doc_count": 3
},
{
"key": "2分",
"doc_count": 1
}
]
}
}
}
java代码为
String label = "your_label";
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
TermsAggregationBuilder aggBuilder = AggregationBuilders.terms(label+"_count").field("labels."+label+".keyword").size(20);
searchSourceBuilder.aggregation(aggBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
这时有一个很头疼的问题,得到的响应该如何处理呢,debug很久都没有拿到这个bulket桶对象,这时需要一个Terms对象强转然后用Terms.Bucket接收
Map<String, Integer> map = new HashMap<>();
List<? extends Terms.Bucket> lbucket = ((Terms) searchResponse.getAggregations().asMap().get(label + "_count")).getBuckets();
for (Terms.Bucket l : lbucket) {
map.put(l.getKeyAsString(), (int) l.getDocCount());
}
return map;