Spring 带过滤器的数据 ElasticSearch 聚合

Spring data ElastiSearch aggregations with filters

我正在尝试对按某些条件过滤的值执行聚合。我正在使用 spring 数据的 ElasticSearchTemplate.query() 方法执行查询并在结果提取器中获取结果。 我得到了正确的匹配(即应用了过滤器,并且只检索了与这些值匹配的文档。)。但是,对所有文档执行聚合。我认为聚合应该只应用于过滤后的值。以下是我使用的代码:

SearchQuery query = //get the query    
SearchResponse hits = template.query(query, new ResultsExtractor<SearchResponse>() {
                @Override
                public SearchResponse extract(SearchResponse response) {
                    return response;
                }
            });

为了进一步调试问题,我编写了执行查询的代码,而不是使用 spring 数据。以下是代码:

SearchRequestBuilder builder = esSetup.client().prepareSearch("document");
            builder.setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), query.getFilter()));

            builder.addFields(query.getFields().toArray(new String[query.getFields().size()]));
            for(AbstractAggregationBuilder aggregation : query.getAggregations()){
                builder.addAggregation(aggregation);
            }
            SearchResponse response = builder.get();

令我惊讶的是,此查询正确执行并且过滤器也应用于聚合。为了进一步分析,我查看了elasticsearchtemplate的代码,发现它使用setPostFilter方法来设置过滤器。然后我修改了我的代码以这样设置过滤器:

SearchRequestBuilder builder = esSetup.client().prepareSearch("document");
//          builder.setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), query.getFilter()));
            builder.setPostFilter(query.getFilter());
            builder.addFields(query.getFields().toArray(new String[query.getFields().size()]));
            for(AbstractAggregationBuilder aggregation : query.getAggregations()){
                builder.addAggregation(aggregation);
            }
            SearchResponse response = builder.get();

当我执行上面的代码时,它表现出与 spring 数据相同的行为! (即过滤器应用于查询但不是聚合。 这是spring data es的bug吗?如果没有,那么我是否应该使用任何其他方法以我想要的方式检索数据?

提前致谢。

此行为是 Elasticsearch 的设计使然。

简而言之,聚合和 post 过滤器的输入是与请求正文的 query 部分匹配的文档集。因此,聚合不会应用于过滤后的文档。

但是,如果您确实希望对过滤后的文档应用聚合,"move the filters inside the query section",即使用 filtered query。现在 query 部分的输出将是过滤后的文档集,聚合将按预期应用于它们。

因此,根据您的要求,使用过滤查询而不是 post 过滤器。