Aggregations: Fixes Filter and FiltersAggregation to work with empty query

This fix ensures the filter and filters aggregation will not throw a NPE when `{}` is passed in as a filter. Instead `{}` is interpreted as a MatchAllDocsQuery.

Closes #17518
This commit is contained in:
Colin Goodheart-Smithe 2016-04-05 16:16:07 +01:00
parent 7037670aeb
commit 65a5366cba
5 changed files with 53 additions and 7 deletions

View File

@ -23,6 +23,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.EmptyQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.AggregatorBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories;
@ -51,8 +52,12 @@ public class FilterAggregatorBuilder extends AggregatorBuilder<FilterAggregatorB
if (filter == null) {
throw new IllegalArgumentException("[filter] must not be null: [" + name + "]");
}
if (filter instanceof EmptyQueryBuilder) {
this.filter = new MatchAllQueryBuilder();
} else {
this.filter = filter;
}
}
@Override
protected AggregatorFactory<?> doBuild(AggregationContext context, AggregatorFactory<?> parent,

View File

@ -20,7 +20,6 @@ package org.elasticsearch.search.aggregations.bucket.filter;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.Aggregator;
@ -45,9 +44,7 @@ public class FilterParser implements Aggregator.Parser {
throw new ParsingException(null, "filter cannot be null in filter aggregation [{}]", aggregationName);
}
FilterAggregatorBuilder factory = new FilterAggregatorBuilder(aggregationName,
filter == null ? new MatchAllQueryBuilder() : filter);
return factory;
return new FilterAggregatorBuilder(aggregationName, filter);
}
@Override

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.EmptyQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.Aggregator;
import org.elasticsearch.search.aggregations.AggregatorFactories;
@ -70,8 +71,12 @@ public class FiltersAggregator extends BucketsAggregator {
throw new IllegalArgumentException("[filter] must not be null");
}
this.key = key;
if (filter instanceof EmptyQueryBuilder) {
this.filter = new MatchAllQueryBuilder();
} else {
this.filter = filter;
}
}
public String key() {
return key;

View File

@ -23,6 +23,7 @@ import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.EmptyQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
@ -108,7 +109,18 @@ public class FilterIT extends ESIntegTestCase {
// See NullPointer issue when filters are empty:
// https://github.com/elastic/elasticsearch/issues/8438
public void testEmptyFilterDeclarations() throws Exception {
QueryBuilder emptyFilter = new BoolQueryBuilder();
QueryBuilder<?> emptyFilter = new BoolQueryBuilder();
SearchResponse response = client().prepareSearch("idx").addAggregation(filter("tag1", emptyFilter)).execute().actionGet();
assertSearchResponse(response);
Filter filter = response.getAggregations().get("tag1");
assertThat(filter, notNullValue());
assertThat(filter.getDocCount(), equalTo((long) numDocs));
}
public void testEmptyFilter() throws Exception {
QueryBuilder<?> emptyFilter = new EmptyQueryBuilder();
SearchResponse response = client().prepareSearch("idx").addAggregation(filter("tag1", emptyFilter)).execute().actionGet();
assertSearchResponse(response);

View File

@ -24,6 +24,7 @@ import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.EmptyQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.bucket.filters.Filters;
import org.elasticsearch.search.aggregations.bucket.filters.FiltersAggregator.KeyedFilter;
@ -201,6 +202,32 @@ public class FiltersIT extends ESIntegTestCase {
assertThat((double) propertiesCounts[1], equalTo((double) sum / numTag2Docs));
}
public void testEmptyFilter() throws Exception {
QueryBuilder<?> emptyFilter = new EmptyQueryBuilder();
SearchResponse response = client().prepareSearch("idx").addAggregation(filters("tag1", emptyFilter)).execute().actionGet();
assertSearchResponse(response);
Filters filter = response.getAggregations().get("tag1");
assertThat(filter, notNullValue());
assertThat(filter.getBuckets().size(), equalTo(1));
assertThat(filter.getBuckets().get(0).getDocCount(), equalTo((long) numDocs));
}
public void testEmptyKeyedFilter() throws Exception {
QueryBuilder<?> emptyFilter = new EmptyQueryBuilder();
SearchResponse response = client().prepareSearch("idx").addAggregation(filters("tag1", new KeyedFilter("foo", emptyFilter)))
.execute().actionGet();
assertSearchResponse(response);
Filters filter = response.getAggregations().get("tag1");
assertThat(filter, notNullValue());
assertThat(filter.getBuckets().size(), equalTo(1));
assertThat(filter.getBuckets().get(0).getKey(), equalTo("foo"));
assertThat(filter.getBuckets().get(0).getDocCount(), equalTo((long) numDocs));
}
public void testAsSubAggregation() {
SearchResponse response = client().prepareSearch("idx")
.addAggregation(