Java中使用ES分页查询aggregations中的结果

  • A+
所属分类:全文检索

最近做一个需求时,需要对ES中的数据按某个字段分组统计个数,所以用到了ES的aggregations分组,我本以为ES默认会返回所有分组的结果,但实际看日志才发现aggregations的条件中默认带上了size=10,所以默认只会返回10条分组的结果

那么如果我想返回所有的结果怎么办?网上一般的做法是手动指定aggregation的size为一个很大的数,比如10000,这样就可以返回10000条分组结果了。本来我也打算这样做的,但是一个问题是,我确认了实际的数据,用kibana执行的结果中分组的条数有10万以上。所以这种方法就不太适用了,必须得分页获取了。

于是我开始在网上查如何分页获取aggregations中的分组结果,但是结果不令人满意,不管是百度,还是google,还是chatGPT,给出的方法都是使用search after或scroll来分页,但是这两种我都试验了下,都是查询明细的分页方式,而不是aggregations中的分页。

于是,我只能自己想办法实现了,基于search after的思路,我想到了一个办法,由于我分组的这个字段是一个雪花算法生成的id,所以是可以比较大小的,那么我aggregations里按这个分组字段升序,然后每次取到分组结果中的最后一条数据,下一次查询条件中带上id > 最后一条数据id,这样不就从上次最后一条数据之后开始取了吗?

于是写完代码验证无误。关键代码如下:

BoolQueryBuilder boolQueryBuilder = QueryBuilders
                .boolQuery()
                .mustNot(QueryBuilders.existsQuery("deleted_at"));
        boolQueryBuilder.must(queryBuilder);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.sort(SortBuilders.fieldSort("user_id").order(SortOrder.ASC));
        searchSourceBuilder.size(0);
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("group_cnt")
                .field(groupByColumn).order(BucketOrder.key(true));
        aggregationBuilder.size(10000);
        searchSourceBuilder.aggregation(aggregationBuilder);

        if (lastSortValue != null) {
                boolQueryBuilder.must(QueryBuilders.rangeQuery("user_id").gt(lastSortValue));
            }

            SearchResponse searchResponse = this.search(esIndex, searchSourceBuilder);

           Terms aggregation = searchResponse.getAggregations().get("group_cnt");

            if (ObjectUtils.isEmpty(aggregation.getBuckets())) {
                return result;
            }

            for (Terms.Bucket bucket : aggregation.getBuckets()) {
                String group = bucket.getKeyAsString();
                Long count = bucket.getDocCount();
            }

            Terms.Bucket lastBucket = aggregation.getBuckets().get(aggregation.getBuckets().size() - 1);
            lastSortValue = lastBucket.getKeyAsString();

 

ZPY

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: