【原创】Java使用RestHighLevelClient操作ElasticSearch,实现多字段Group by并将结果进行count排序

前言

之前写过一篇使用RestHighLevelClient进行多字段group by的(【原创】ElasticSearch使用Java代码group by多个字段查询统计数量_DCTANT的博客-CSDN博客_elasticsearch分组统计 java),其实那篇并不完美,最佳的group by方法应该用script,而不是像之前那篇博客一样去递归求和,虽然也不是不行,但是这个毕竟太暴力了,效率也不高。

直接上代码:

初始化RestHighLevelClient我这边为了节省篇幅先跳过了,直接上核心:

SearchRequest searchRequest = new SearchRequest(index);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

//为了保持顺序,使用LinkedHashMap,防止进入map后变成乱序排列
LinkedHashMap<String, Long> nameCountMap = new LinkedHashMap<>();
//group by后再order by
BucketOrder bucketOrder = BucketOrder.count(false); //这里的count方法中true表示升序排列,false代表降序排列
AggregationBuilder aggregationBuilder = AggregationBuilders.terms("${分组名}") //分组名可以随便填,但是必须和后面aggregations.get("${分组名}");里面填的分组名保持一致,否则会返回null,导致后续空指针异常
                                                           .script(new Script("doc['${字段1}'].value+'@@'+doc['${字段2}'].value+'@@'+doc['${字段3}'].value+'@@'+doc['${字段4}'].value")) //相当于group by 4个字段,其中的@@是字段间的分隔符,最后ES返回的结果是这样的${字段1}@@${字段2}@@${字段3}@@${字段4}
                                                           .size(20) //聚合返回20个值(不传默认返回10个值)
                                                           .order(bucketOrder); //将上方的排序填入,让ES进行排序
sourceBuilder.aggregation(aggregationBuilder); //填入分组信息
searchRequest.source(sourceBuilder);
try {
    SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    Aggregations aggregations = searchResponse.getAggregations();
    Terms terms = aggregations.get("${分组名}"); //填入上方terms()中相同的分组名
    for (Terms.Bucket bucket : terms.getBuckets()) {
        String key = bucket.getKeyAsString(); //这里的key值是这样的:${字段1}@@${字段2}@@${字段3}@@${字段4}
        long count = bucket.getDocCount(); //group by后聚合统计出来的数量
        String[] split = key.split("@@"); //切开作为分隔符的@@,取里面需要的字段放入nameCountMap就行了
        nameCountMap.put(split[0], count); //假设取第0个字段作为key
    }
} catch (IOException e) {
    e.printStackTrace();
}
// todo 处理剩下的业务逻辑

看一下注释应该就能懂了,相当于ES的查询为:

{
    "aggs":{
        "myStatistic":{
            "terms":{
                "script":{
                    "inline":"doc['字段1'].value+'@@'+doc['字段2'].value+'@@'+doc['字段3'].value+'@@'+doc['字段4'].value"
                },
                "size":20,
                "order":{
                    "_count":"desc"
                }
            }
     
        }
    }
}

参考链接:Elasticsearch入门 ,使用 script 做聚合查询 - 简书

如果script中的字段,其中有个值不存在则会报这个错:

ElasticSeach 采坑之A document doesn‘t have a value for a field! Use doc[<field>].size()==0 to check if_JAVA探索的博客-CSDN博客

解决方案如这个博客所示,我这边不再赘述

猜你喜欢

转载自blog.csdn.net/DCTANT/article/details/124921862