Skip to content

Commit 7feb19a

Browse files
authored
Make sure non-collecting aggs include sub-aggs (elastic#64214)
Now that we're consistently using `cat_match` to filter which shards we run on we can get this confusing case: 1. You have a search with, say, a range and a sub-agg. 2. That search has a query that `can_match` can recognize will match no docs. On *any* shard. 3. So we dutifully run it on a single shard so it can produce the "empty" aggs. 4. The shard we pick happens to not have the target of the range mapped. 5. This kicks in the special range aggregator that doesn't collect any documents. 6. Before this commit, that range aggregator *also* never produced any sub-aggs. So, without this change, it was quite possible for a search that happened to match no documents to "throw away" the sub-aggs of a range and a few other aggs. We've had this problem for a long, long time but it is more confusing now because `can_match` is really kicking in and causing us to see cases where it looks like you are targeting a lot of shards but you really are only targeting a couple. It used to be that to get the "no sub-aggs" behavior you had to explicitly target only shards that didn't map the target field of the `range` agg. And, like, in that case it isn't too bad because you targeted a sort of degenerate shard. But now that `can_match` is doing its thing you can end up with the confusing steps above. It took me several hours to track down what what happening I know how the individual pieces of all of this works. It took four hours to figure out how they fit together in this case.... Anyway! This replaces all the aggregator implementations that throw out the sub-aggregators with ones that keep them. I think this'll be less confusing in the future. Closes elastic#64142
1 parent eaac649 commit 7feb19a

File tree

12 files changed

+62
-24
lines changed

12 files changed

+62
-24
lines changed

modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ChildrenAggregatorFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public ChildrenAggregatorFactory(String name,
6060

6161
@Override
6262
protected Aggregator createUnmapped(SearchContext searchContext, Aggregator parent, Map<String, Object> metadata) throws IOException {
63-
return new NonCollectingAggregator(name, searchContext, parent, metadata) {
63+
return new NonCollectingAggregator(name, searchContext, parent, factories, metadata) {
6464
@Override
6565
public InternalAggregation buildEmptyAggregation() {
6666
return new InternalChildren(name, 0, buildEmptySubAggregations(), metadata());

modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ParentAggregatorFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public ParentAggregatorFactory(String name,
6060

6161
@Override
6262
protected Aggregator createUnmapped(SearchContext searchContext, Aggregator parent, Map<String, Object> metadata) throws IOException {
63-
return new NonCollectingAggregator(name, searchContext, parent, metadata) {
63+
return new NonCollectingAggregator(name, searchContext, parent, factories, metadata) {
6464
@Override
6565
public InternalAggregation buildEmptyAggregation() {
6666
return new InternalParent(name, 0, buildEmptySubAggregations(), metadata());

rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/40_range.yml

+36
Original file line numberDiff line numberDiff line change
@@ -384,3 +384,39 @@ setup:
384384
- match: { aggregations.age_groups.buckets.2.key: "Generation Y" }
385385

386386
- match: { aggregations.age_groups.buckets.2.doc_count: 2 }
387+
388+
389+
---
390+
"Date range unmapped with children":
391+
- do:
392+
indices.create:
393+
index: test_a_unmapped
394+
body:
395+
settings:
396+
number_of_shards: 1
397+
number_of_replicas: 0
398+
- do:
399+
search:
400+
index: test_a_unmapped
401+
body:
402+
size: 0
403+
query:
404+
terms:
405+
animal: []
406+
aggs:
407+
date_range:
408+
date_range:
409+
field: date
410+
ranges:
411+
- from: 2020-01-01T00:00:00Z
412+
aggs:
413+
sounds:
414+
cardinality:
415+
field: sound.keyword
416+
417+
- match: { hits.total.value: 0 }
418+
- length: { aggregations.date_range.buckets: 1 }
419+
- match: { aggregations.date_range.buckets.0.doc_count: 0 }
420+
- match: { aggregations.date_range.buckets.0.key: "2020-01-01T00:00:00.000Z-*" }
421+
- is_false: aggregations.date_range.buckets.0.to
422+
- match: { aggregations.date_range.buckets.0.sounds.value: 0 }

server/src/main/java/org/elasticsearch/search/aggregations/NonCollectingAggregator.java

-8
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,6 @@ protected NonCollectingAggregator(String name, SearchContext context, Aggregator
3838
super(name, subFactories, context, parent, CardinalityUpperBound.NONE, metadata);
3939
}
4040

41-
/**
42-
* Build a {@linkplain NonCollectingAggregator} for an aggregator without sub-aggregators.
43-
*/
44-
protected NonCollectingAggregator(String name, SearchContext context, Aggregator parent,
45-
Map<String, Object> metadata) throws IOException {
46-
this(name, context, parent, AggregatorFactories.EMPTY, metadata);
47-
}
48-
4941
@Override
5042
public final LeafBucketCollector getLeafCollector(LeafReaderContext reader, LeafBucketCollector sub) {
5143
// the framework will automatically eliminate it

server/src/main/java/org/elasticsearch/search/aggregations/bucket/geogrid/GeoHashGridAggregatorFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ protected Aggregator createUnmapped(SearchContext searchContext,
6363
Aggregator parent,
6464
Map<String, Object> metadata) throws IOException {
6565
final InternalAggregation aggregation = new InternalGeoHashGrid(name, requiredSize, emptyList(), metadata);
66-
return new NonCollectingAggregator(name, searchContext, parent, metadata) {
66+
return new NonCollectingAggregator(name, searchContext, parent, factories, metadata) {
6767
@Override
6868
public InternalAggregation buildEmptyAggregation() {
6969
return aggregation;

server/src/main/java/org/elasticsearch/search/aggregations/bucket/geogrid/GeoTileGridAggregatorFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected Aggregator createUnmapped(SearchContext searchContext,
6161
Aggregator parent,
6262
Map<String, Object> metadata) throws IOException {
6363
final InternalAggregation aggregation = new InternalGeoTileGrid(name, requiredSize, Collections.emptyList(), metadata);
64-
return new NonCollectingAggregator(name, searchContext, parent, metadata) {
64+
return new NonCollectingAggregator(name, searchContext, parent, factories, metadata) {
6565
@Override
6666
public InternalAggregation buildEmptyAggregation() {
6767
return aggregation;

server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorFactory.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public Aggregator createInternal(SearchContext searchContext,
5151
CardinalityUpperBound cardinality,
5252
Map<String, Object> metadata) throws IOException {
5353
if (childObjectMapper == null) {
54-
return new Unmapped(name, searchContext, parent, metadata);
54+
return new Unmapped(name, searchContext, parent, factories, metadata);
5555
}
5656
return new NestedAggregator(name, factories, parentObjectMapper, childObjectMapper, searchContext, parent,
5757
cardinality, metadata);
@@ -62,8 +62,9 @@ private static final class Unmapped extends NonCollectingAggregator {
6262
Unmapped(String name,
6363
SearchContext context,
6464
Aggregator parent,
65+
AggregatorFactories factories,
6566
Map<String, Object> metadata) throws IOException {
66-
super(name, context, parent, metadata);
67+
super(name, context, parent, factories, metadata);
6768
}
6869

6970
@Override

server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregatorFactory.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public Aggregator createInternal(SearchContext searchContext,
5252
CardinalityUpperBound cardinality,
5353
Map<String, Object> metadata) throws IOException {
5454
if (unmapped) {
55-
return new Unmapped(name, searchContext, parent, metadata);
55+
return new Unmapped(name, searchContext, parent, factories, metadata);
5656
} else {
5757
return new ReverseNestedAggregator(name, factories, parentObjectMapper,
5858
searchContext, parent, cardinality, metadata);
@@ -64,8 +64,9 @@ private static final class Unmapped extends NonCollectingAggregator {
6464
Unmapped(String name,
6565
SearchContext context,
6666
Aggregator parent,
67+
AggregatorFactories factories,
6768
Map<String, Object> metadata) throws IOException {
68-
super(name, context, parent, metadata);
69+
super(name, context, parent, factories, metadata);
6970
}
7071

7172
@Override

server/src/main/java/org/elasticsearch/search/aggregations/bucket/range/AbstractRangeAggregatorFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public AbstractRangeAggregatorFactory(String name,
7676
protected Aggregator createUnmapped(SearchContext searchContext,
7777
Aggregator parent,
7878
Map<String, Object> metadata) throws IOException {
79-
return new Unmapped<>(name, ranges, keyed, config.format(), searchContext, parent, rangeFactory, metadata);
79+
return new Unmapped<>(name, factories, ranges, keyed, config.format(), searchContext, parent, rangeFactory, metadata);
8080
}
8181

8282
@Override

server/src/main/java/org/elasticsearch/search/aggregations/bucket/range/GeoDistanceRangeAggregatorFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public GeoDistanceRangeAggregatorFactory(String name, ValuesSourceConfig config,
107107
protected Aggregator createUnmapped(SearchContext searchContext,
108108
Aggregator parent,
109109
Map<String, Object> metadata) throws IOException {
110-
return new RangeAggregator.Unmapped<>(name, ranges, keyed, config.format(), searchContext, parent,
110+
return new RangeAggregator.Unmapped<>(name, factories, ranges, keyed, config.format(), searchContext, parent,
111111
rangeFactory, metadata);
112112
}
113113

server/src/main/java/org/elasticsearch/search/aggregations/bucket/range/RangeAggregator.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,19 @@ public static class Unmapped<R extends RangeAggregator.Range> extends NonCollect
353353
private final InternalRange.Factory factory;
354354
private final DocValueFormat format;
355355

356-
public Unmapped(String name, R[] ranges, boolean keyed, DocValueFormat format, SearchContext context, Aggregator parent,
357-
InternalRange.Factory factory, Map<String, Object> metadata)
358-
throws IOException {
359-
360-
super(name, context, parent, metadata);
356+
public Unmapped(
357+
String name,
358+
AggregatorFactories factories,
359+
R[] ranges,
360+
boolean keyed,
361+
DocValueFormat format,
362+
SearchContext context,
363+
Aggregator parent,
364+
InternalRange.Factory factory,
365+
Map<String, Object> metadata
366+
) throws IOException {
367+
368+
super(name, context, parent, factories, metadata);
361369
this.ranges = ranges;
362370
this.keyed = keyed;
363371
this.format = format;

server/src/main/java/org/elasticsearch/search/aggregations/bucket/terms/SignificantTermsAggregatorFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ protected Aggregator createUnmapped(SearchContext searchContext,
186186
Map<String, Object> metadata) throws IOException {
187187
final InternalAggregation aggregation = new UnmappedSignificantTerms(name, bucketCountThresholds.getRequiredSize(),
188188
bucketCountThresholds.getMinDocCount(), metadata);
189-
return new NonCollectingAggregator(name, searchContext, parent, metadata) {
189+
return new NonCollectingAggregator(name, searchContext, parent, factories, metadata) {
190190
@Override
191191
public InternalAggregation buildEmptyAggregation() {
192192
return aggregation;

0 commit comments

Comments
 (0)