Fix preserving FiltersAggregationBuilder#keyed field on rewrite (#27900)

Currently FiltersAggregationBuilder#doRewrite creates a new FiltersAggregationBuilder which doesn't correctly copy the original "keyed" field if a non-keyed filter gets rewritten.
This can cause rendering bugs of the output aggregations like the one reported in #27841.

Closes #27841
This commit is contained in:
Christoph Büscher 2017-12-19 19:56:12 +01:00 committed by GitHub
parent 41677b0b9e
commit fb2fd4e8ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 6 deletions

View File

@ -65,15 +65,19 @@ public class FiltersAggregationBuilder extends AbstractAggregationBuilder<Filter
* the KeyedFilters to use with this aggregation.
*/
public FiltersAggregationBuilder(String name, KeyedFilter... filters) {
this(name, Arrays.asList(filters));
this(name, Arrays.asList(filters), true);
}
private FiltersAggregationBuilder(String name, List<KeyedFilter> filters) {
private FiltersAggregationBuilder(String name, List<KeyedFilter> filters, boolean keyed) {
super(name);
// internally we want to have a fixed order of filters, regardless of the order of the filters in the request
this.filters = new ArrayList<>(filters);
Collections.sort(this.filters, (KeyedFilter kf1, KeyedFilter kf2) -> kf1.key().compareTo(kf2.key()));
this.keyed = true;
if (keyed) {
// internally we want to have a fixed order of filters, regardless of the order of the filters in the request
Collections.sort(this.filters, (KeyedFilter kf1, KeyedFilter kf2) -> kf1.key().compareTo(kf2.key()));
this.keyed = true;
} else {
this.keyed = false;
}
}
/**
@ -152,6 +156,13 @@ public class FiltersAggregationBuilder extends AbstractAggregationBuilder<Filter
return Collections.unmodifiableList(this.filters);
}
/**
* @return true if this builders filters have a key
*/
public boolean isKeyed() {
return this.keyed;
}
/**
* Set the key to use for the bucket for documents not matching any
* filter.
@ -184,7 +195,7 @@ public class FiltersAggregationBuilder extends AbstractAggregationBuilder<Filter
}
}
if (changed) {
return new FiltersAggregationBuilder(getName(), rewrittenFilters);
return new FiltersAggregationBuilder(getName(), rewrittenFilters, this.keyed);
} else {
return this;
}

View File

@ -23,15 +23,21 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryRewriteContext;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.BaseAggregationTestCase;
import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.FiltersAggregator.KeyedFilter;
import java.io.IOException;
import static org.hamcrest.Matchers.instanceOf;
public class FiltersTests extends BaseAggregationTestCase<FiltersAggregationBuilder> {
@Override
@ -113,4 +119,38 @@ public class FiltersTests extends BaseAggregationTestCase<FiltersAggregationBuil
// unless the other bucket is explicitly disabled
assertFalse(filters.otherBucket());
}
public void testRewrite() throws IOException {
// test non-keyed filter that doesn't rewrite
AggregationBuilder original = new FiltersAggregationBuilder("my-agg", new MatchAllQueryBuilder());
AggregationBuilder rewritten = original.rewrite(new QueryRewriteContext(xContentRegistry(), null, null, () -> 0L));
assertSame(original, rewritten);
// test non-keyed filter that does rewrite
original = new FiltersAggregationBuilder("my-agg", new BoolQueryBuilder());
rewritten = original.rewrite(new QueryRewriteContext(xContentRegistry(), null, null, () -> 0L));
assertNotSame(original, rewritten);
assertThat(rewritten, instanceOf(FiltersAggregationBuilder.class));
assertEquals("my-agg", ((FiltersAggregationBuilder) rewritten).getName());
assertEquals(1, ((FiltersAggregationBuilder) rewritten).filters().size());
assertEquals("0", ((FiltersAggregationBuilder) rewritten).filters().get(0).key());
assertThat(((FiltersAggregationBuilder) rewritten).filters().get(0).filter(), instanceOf(MatchAllQueryBuilder.class));
assertFalse(((FiltersAggregationBuilder) rewritten).isKeyed());
// test keyed filter that doesn't rewrite
original = new FiltersAggregationBuilder("my-agg", new KeyedFilter("my-filter", new MatchAllQueryBuilder()));
rewritten = original.rewrite(new QueryRewriteContext(xContentRegistry(), null, null, () -> 0L));
assertSame(original, rewritten);
// test non-keyed filter that does rewrite
original = new FiltersAggregationBuilder("my-agg", new KeyedFilter("my-filter", new BoolQueryBuilder()));
rewritten = original.rewrite(new QueryRewriteContext(xContentRegistry(), null, null, () -> 0L));
assertNotSame(original, rewritten);
assertThat(rewritten, instanceOf(FiltersAggregationBuilder.class));
assertEquals("my-agg", ((FiltersAggregationBuilder) rewritten).getName());
assertEquals(1, ((FiltersAggregationBuilder) rewritten).filters().size());
assertEquals("my-filter", ((FiltersAggregationBuilder) rewritten).filters().get(0).key());
assertThat(((FiltersAggregationBuilder) rewritten).filters().get(0).filter(), instanceOf(MatchAllQueryBuilder.class));
assertTrue(((FiltersAggregationBuilder) rewritten).isKeyed());
}
}

View File

@ -246,6 +246,22 @@ setup:
- match: { aggregations.the_filter.buckets.second_filter.doc_count: 1 }
- match: { aggregations.the_filter.meta.foo: "bar" }
---
"Single anonymous bool query":
- do:
search:
body:
aggs:
the_filter:
filters:
filters:
- bool: {}
- match: { hits.total: 4 }
- length: { hits.hits: 4 }
- match: { aggregations.the_filter.buckets.0.doc_count: 4 }
---
"Bad params":