Skip to content

Commit 0806190

Browse files
committed
Merge pull request #15998 from jpountz/fix/filter_agg_creates_meights_once
Filter(s) aggregation should create weights only once.
2 parents a05ea53 + cc41e6e commit 0806190

File tree

4 files changed

+88
-15
lines changed

4 files changed

+88
-15
lines changed

core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregator.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.elasticsearch.search.aggregations.bucket.filter;
2020

2121
import org.apache.lucene.index.LeafReaderContext;
22+
import org.apache.lucene.search.IndexSearcher;
2223
import org.apache.lucene.search.Query;
2324
import org.apache.lucene.search.Weight;
2425
import org.apache.lucene.util.Bits;
@@ -45,13 +46,13 @@ public class FilterAggregator extends SingleBucketAggregator {
4546
private final Weight filter;
4647

4748
public FilterAggregator(String name,
48-
Query filter,
49+
Weight filter,
4950
AggregatorFactories factories,
5051
AggregationContext aggregationContext,
5152
Aggregator parent, List<PipelineAggregator> pipelineAggregators,
5253
Map<String, Object> metaData) throws IOException {
5354
super(name, factories, aggregationContext, parent, pipelineAggregators, metaData);
54-
this.filter = aggregationContext.searchContext().searcher().createNormalizedWeight(filter, false);
55+
this.filter = filter;
5556
}
5657

5758
@Override
@@ -89,10 +90,22 @@ public Factory(String name, Query filter) {
8990
this.filter = filter;
9091
}
9192

93+
// TODO: refactor in order to initialize the factory once with its parent,
94+
// the context, etc. and then have a no-arg lightweight create method
95+
// (since create may be called thousands of times)
96+
97+
private IndexSearcher searcher;
98+
private Weight weight;
99+
92100
@Override
93101
public Aggregator createInternal(AggregationContext context, Aggregator parent, boolean collectsFromSingleBucket,
94102
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {
95-
return new FilterAggregator(name, filter, factories, context, parent, pipelineAggregators, metaData);
103+
IndexSearcher contextSearcher = context.searchContext().searcher();
104+
if (searcher != contextSearcher) {
105+
searcher = contextSearcher;
106+
weight = contextSearcher.createNormalizedWeight(filter, false);
107+
}
108+
return new FilterAggregator(name, weight, factories, context, parent, pipelineAggregators, metaData);
96109
}
97110

98111
}

core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregator.java

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.search.aggregations.bucket.filters;
2121

2222
import org.apache.lucene.index.LeafReaderContext;
23+
import org.apache.lucene.search.IndexSearcher;
2324
import org.apache.lucene.search.Query;
2425
import org.apache.lucene.search.Weight;
2526
import org.apache.lucene.util.Bits;
@@ -57,31 +58,26 @@ static class KeyedFilter {
5758
}
5859

5960
private final String[] keys;
60-
private final Weight[] filters;
61+
private Weight[] filters;
6162
private final boolean keyed;
6263
private final boolean showOtherBucket;
6364
private final String otherBucketKey;
6465
private final int totalNumKeys;
6566

66-
public FiltersAggregator(String name, AggregatorFactories factories, List<KeyedFilter> filters, boolean keyed, String otherBucketKey,
67+
public FiltersAggregator(String name, AggregatorFactories factories, String[] keys, Weight[] filters, boolean keyed, String otherBucketKey,
6768
AggregationContext aggregationContext,
6869
Aggregator parent, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData)
6970
throws IOException {
7071
super(name, factories, aggregationContext, parent, pipelineAggregators, metaData);
7172
this.keyed = keyed;
72-
this.keys = new String[filters.size()];
73-
this.filters = new Weight[filters.size()];
73+
this.keys = keys;
74+
this.filters = filters;
7475
this.showOtherBucket = otherBucketKey != null;
7576
this.otherBucketKey = otherBucketKey;
7677
if (showOtherBucket) {
77-
this.totalNumKeys = filters.size() + 1;
78+
this.totalNumKeys = keys.length + 1;
7879
} else {
79-
this.totalNumKeys = filters.size();
80-
}
81-
for (int i = 0; i < filters.size(); ++i) {
82-
KeyedFilter keyedFilter = filters.get(i);
83-
this.keys[i] = keyedFilter.key;
84-
this.filters[i] = aggregationContext.searchContext().searcher().createNormalizedWeight(keyedFilter.filter, false);
80+
this.totalNumKeys = keys.length;
8581
}
8682
}
8783

@@ -146,6 +142,7 @@ final long bucketOrd(long owningBucketOrdinal, int filterOrd) {
146142
public static class Factory extends AggregatorFactory {
147143

148144
private final List<KeyedFilter> filters;
145+
private final String[] keys;
149146
private boolean keyed;
150147
private String otherBucketKey;
151148

@@ -154,12 +151,33 @@ public Factory(String name, List<KeyedFilter> filters, boolean keyed, String oth
154151
this.filters = filters;
155152
this.keyed = keyed;
156153
this.otherBucketKey = otherBucketKey;
154+
this.keys = new String[filters.size()];
155+
for (int i = 0; i < filters.size(); ++i) {
156+
KeyedFilter keyedFilter = filters.get(i);
157+
this.keys[i] = keyedFilter.key;
158+
}
157159
}
158160

161+
// TODO: refactor in order to initialize the factory once with its parent,
162+
// the context, etc. and then have a no-arg lightweight create method
163+
// (since create may be called thousands of times)
164+
165+
private IndexSearcher searcher;
166+
private Weight[] weights;
167+
159168
@Override
160169
public Aggregator createInternal(AggregationContext context, Aggregator parent, boolean collectsFromSingleBucket,
161170
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {
162-
return new FiltersAggregator(name, factories, filters, keyed, otherBucketKey, context, parent, pipelineAggregators, metaData);
171+
IndexSearcher contextSearcher = context.searchContext().searcher();
172+
if (searcher != contextSearcher) {
173+
searcher = contextSearcher;
174+
weights = new Weight[filters.size()];
175+
for (int i = 0; i < filters.size(); ++i) {
176+
KeyedFilter keyedFilter = filters.get(i);
177+
this.weights[i] = contextSearcher.createNormalizedWeight(keyedFilter.filter, false);
178+
}
179+
}
180+
return new FiltersAggregator(name, factories, keys, weights, keyed, otherBucketKey, context, parent, pipelineAggregators, metaData);
163181
}
164182
}
165183

core/src/test/java/org/elasticsearch/search/aggregations/bucket/FilterIT.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
4343
import static org.hamcrest.Matchers.equalTo;
4444
import static org.hamcrest.Matchers.is;
45+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
4546
import static org.hamcrest.core.IsNull.notNullValue;
4647

4748
/**
@@ -145,6 +146,25 @@ public void testWithSubAggregation() throws Exception {
145146
assertThat((double) filter.getProperty("avg_value.value"), equalTo((double) sum / numTag1Docs));
146147
}
147148

149+
public void testAsSubAggregation() {
150+
SearchResponse response = client().prepareSearch("idx")
151+
.addAggregation(
152+
histogram("histo").field("value").interval(2L).subAggregation(
153+
filter("filter").filter(matchAllQuery()))).get();
154+
155+
assertSearchResponse(response);
156+
157+
Histogram histo = response.getAggregations().get("histo");
158+
assertThat(histo, notNullValue());
159+
assertThat(histo.getBuckets().size(), greaterThanOrEqualTo(1));
160+
161+
for (Histogram.Bucket bucket : histo.getBuckets()) {
162+
Filter filter = bucket.getAggregations().get("filter");
163+
assertThat(filter, notNullValue());
164+
assertEquals(bucket.getDocCount(), filter.getDocCount());
165+
}
166+
}
167+
148168
public void testWithContextBasedSubAggregation() throws Exception {
149169
try {
150170
client().prepareSearch("idx")

core/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersIT.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import static org.elasticsearch.search.aggregations.AggregationBuilders.histogram;
4545
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
4646
import static org.hamcrest.Matchers.equalTo;
47+
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
4748
import static org.hamcrest.Matchers.is;
4849
import static org.hamcrest.core.IsNull.notNullValue;
4950

@@ -205,6 +206,27 @@ public void testWithSubAggregation() throws Exception {
205206
assertThat((double) propertiesCounts[1], equalTo((double) sum / numTag2Docs));
206207
}
207208

209+
public void testAsSubAggregation() {
210+
SearchResponse response = client().prepareSearch("idx")
211+
.addAggregation(
212+
histogram("histo").field("value").interval(2L).subAggregation(
213+
filters("filters").filter(matchAllQuery()))).get();
214+
215+
assertSearchResponse(response);
216+
217+
Histogram histo = response.getAggregations().get("histo");
218+
assertThat(histo, notNullValue());
219+
assertThat(histo.getBuckets().size(), greaterThanOrEqualTo(1));
220+
221+
for (Histogram.Bucket bucket : histo.getBuckets()) {
222+
Filters filters = bucket.getAggregations().get("filters");
223+
assertThat(filters, notNullValue());
224+
assertThat(filters.getBuckets().size(), equalTo(1));
225+
Filters.Bucket filterBucket = filters.getBuckets().get(0);
226+
assertEquals(bucket.getDocCount(), filterBucket.getDocCount());
227+
}
228+
}
229+
208230
public void testWithContextBasedSubAggregation() throws Exception {
209231

210232
try {

0 commit comments

Comments
 (0)