Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/124782.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 124782
summary: "Aggs: Let terms run in global ords mode no match"
area: Aggregations
type: bug
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ private static TermsAggregatorSupplier bytesSupplier() {
execution = ExecutionMode.fromString(executionHint);
}
// In some cases, using ordinals is just not supported: override it
if (valuesSource.hasOrdinals() == false || matchNoDocs(context, parent)) {
if (valuesSource.hasOrdinals() == false) {
execution = ExecutionMode.MAP;
}
if (matchNoDocs(context, parent) && bucketCountThresholds.getMinDocCount() > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this should not kick in if the user sends a hint. We can run this in Global Ordinals mode, even if it's expensive, and if the user is asking to do that, it might be for a good reason.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a patch.

execution = ExecutionMode.MAP;
}
if (execution == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ public void testMatchNoDocsQuery() throws Exception {
createIndex,
(InternalTerms<?, ?> result) -> { assertEquals(0, result.getBuckets().size()); },
new AggTestConfig(aggregationBuilder, fieldType).withQuery(new MatchNoDocsQuery())
.withCheckAggregator(checkTopLevelAggregatorNoRewrites(TermsAggregatorFactory.ExecutionMode.MAP))
);

debugTestCase(aggregationBuilder, new MatchNoDocsQuery(), createIndex, (result, impl, debug) -> {
Expand Down Expand Up @@ -337,7 +338,6 @@ public void testStringShardZeroMinDocCount() throws IOException {
.executionHint(executionMode.toString())
.size(2)
.minDocCount(0)
.executionHint("map")
.excludeDeletedDocs(true)
.order(BucketOrder.key(true));

Expand All @@ -360,7 +360,80 @@ public void testStringShardZeroMinDocCount() throws IOException {
assertEquals("b", result.getBuckets().get(1).getKeyAsString());
}
assertEquals(0L, result.getBuckets().get(1).getDocCount());
}, new AggTestConfig(aggregationBuilder, fieldType).withQuery(new TermQuery(new Term("string", "e"))));
},
new AggTestConfig(aggregationBuilder, fieldType).withQuery(new TermQuery(new Term("string", "e")))
.withCheckAggregator(checkTopLevelAggregatorNoRewrites(executionMode))
);
}

{
boolean delete = randomBoolean();
// force single shard/segment
testCase(iw -> {
// force single shard/segment
iw.addDocuments(
Arrays.asList(doc(fieldType, "a"), doc(fieldType, "c", "d"), doc(fieldType, "b", "d"), doc(fieldType, "b"))
);
if (delete) {
iw.deleteDocuments(new TermQuery(new Term("string", "b")));
}
}, (InternalTerms<?, ?> result) -> {
assertEquals(2, result.getBuckets().size());
assertEquals("a", result.getBuckets().get(0).getKeyAsString());
assertEquals(0L, result.getBuckets().get(0).getDocCount());
if (delete) {
assertEquals("c", result.getBuckets().get(1).getKeyAsString());
} else {
assertEquals("b", result.getBuckets().get(1).getKeyAsString());
}
assertEquals(0L, result.getBuckets().get(1).getDocCount());
},
new AggTestConfig(aggregationBuilder, fieldType).withQuery(new TermQuery(new Term("string", "e")))
.withCheckAggregator(checkTopLevelAggregatorNoRewrites(executionMode))
);
}
}
}

/**
* Asserts that sane output for {@code min_doc_count: 0} when the top level
* query is {@code match_none}. Especially important is that we respect the
* execution hint in this case. It's a lot faster to collect {@code min_doc_count: 0}
* via ordinals.
*/
public void testStringZeroMinDocCountMatchNone() throws IOException {
MappedFieldType fieldType = new KeywordFieldMapper.KeywordFieldType("string", true, true, Collections.emptyMap());
for (TermsAggregatorFactory.ExecutionMode executionMode : TermsAggregatorFactory.ExecutionMode.values()) {
TermsAggregationBuilder aggregationBuilder = new TermsAggregationBuilder("_name").field("string")
.executionHint(executionMode.toString())
.size(2)
.minDocCount(0)
.excludeDeletedDocs(true)
.order(BucketOrder.key(true));

{
boolean delete = randomBoolean();
// force single shard/segment
testCase(iw -> {
// force single shard/segment
iw.addDocuments(Arrays.asList(doc(fieldType, "a"), doc(fieldType, "b"), doc(fieldType, "c"), doc(fieldType, "d")));
if (delete) {
iw.deleteDocuments(new TermQuery(new Term("string", "b")));
}
}, (InternalTerms<?, ?> result) -> {
assertEquals(2, result.getBuckets().size());
assertEquals("a", result.getBuckets().get(0).getKeyAsString());
assertEquals(0L, result.getBuckets().get(0).getDocCount());
if (delete) {
assertEquals("c", result.getBuckets().get(1).getKeyAsString());
} else {
assertEquals("b", result.getBuckets().get(1).getKeyAsString());
}
assertEquals(0L, result.getBuckets().get(1).getDocCount());
},
new AggTestConfig(aggregationBuilder, fieldType).withQuery(new MatchNoDocsQuery())
.withCheckAggregator(checkTopLevelAggregatorNoRewrites(executionMode))
);
}

{
Expand All @@ -384,7 +457,10 @@ public void testStringShardZeroMinDocCount() throws IOException {
assertEquals("b", result.getBuckets().get(1).getKeyAsString());
}
assertEquals(0L, result.getBuckets().get(1).getDocCount());
}, new AggTestConfig(aggregationBuilder, fieldType).withQuery(new TermQuery(new Term("string", "e"))));
},
new AggTestConfig(aggregationBuilder, fieldType).withQuery(new MatchNoDocsQuery())
.withCheckAggregator(checkTopLevelAggregatorNoRewrites(executionMode))
);
}
}
}
Expand Down Expand Up @@ -2279,4 +2355,11 @@ protected List<ObjectMapper> objectMappers() {
private String randomHint() {
return randomFrom(TermsAggregatorFactory.ExecutionMode.values()).toString();
}

private Consumer<Aggregator> checkTopLevelAggregatorNoRewrites(TermsAggregatorFactory.ExecutionMode executionMode) {
return switch (executionMode) {
case MAP -> a -> assertThat(a, instanceOf(MapStringTermsAggregator.class));
case GLOBAL_ORDINALS -> a -> assertThat(a, instanceOf(GlobalOrdinalsStringTermsAggregator.class));
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ private <A extends InternalAggregation, C extends Aggregator> A searchAndReduce(
}
assertEquals(shouldBeCached, context.isCacheable());
List<InternalAggregation> internalAggregations = List.of(a.buildTopLevel());
aggTestConfig.checkAggregator().accept(a);
assertRoundTrip(internalAggregations);
internalAggs.add(InternalAggregations.from(internalAggregations));
} finally {
Expand Down Expand Up @@ -1703,11 +1704,23 @@ public record AggTestConfig(

boolean useLogDocMergePolicy,
boolean testReductionCancellation,
Consumer<Aggregator> checkAggregator,
MappedFieldType... fieldTypes
) {

public AggTestConfig(AggregationBuilder builder, MappedFieldType... fieldTypes) {
this(new MatchAllDocsQuery(), builder, DEFAULT_MAX_BUCKETS, randomBoolean(), true, randomBoolean(), false, true, fieldTypes);
this(
new MatchAllDocsQuery(),
builder,
DEFAULT_MAX_BUCKETS,
randomBoolean(),
true,
randomBoolean(),
false,
true,
a -> {},
fieldTypes
);
}

public AggTestConfig withQuery(Query query) {
Expand All @@ -1720,6 +1733,7 @@ public AggTestConfig withQuery(Query query) {
incrementalReduce,
useLogDocMergePolicy,
testReductionCancellation,
checkAggregator,
fieldTypes
);
}
Expand All @@ -1734,6 +1748,7 @@ public AggTestConfig withSplitLeavesIntoSeperateAggregators(boolean splitLeavesI
incrementalReduce,
useLogDocMergePolicy,
testReductionCancellation,
checkAggregator,
fieldTypes
);
}
Expand All @@ -1748,6 +1763,7 @@ public AggTestConfig withShouldBeCached(boolean shouldBeCached) {
incrementalReduce,
useLogDocMergePolicy,
testReductionCancellation,
checkAggregator,
fieldTypes
);
}
Expand All @@ -1762,6 +1778,7 @@ public AggTestConfig withMaxBuckets(int maxBuckets) {
incrementalReduce,
useLogDocMergePolicy,
testReductionCancellation,
checkAggregator,
fieldTypes
);
}
Expand All @@ -1776,6 +1793,7 @@ public AggTestConfig withIncrementalReduce(boolean incrementalReduce) {
incrementalReduce,
useLogDocMergePolicy,
testReductionCancellation,
checkAggregator,
fieldTypes
);
}
Expand All @@ -1790,6 +1808,7 @@ public AggTestConfig withLogDocMergePolicy() {
incrementalReduce,
true,
testReductionCancellation,
checkAggregator,
fieldTypes
);
}
Expand All @@ -1804,6 +1823,22 @@ public AggTestConfig noReductionCancellation() {
incrementalReduce,
useLogDocMergePolicy,
false,
checkAggregator,
fieldTypes
);
}

public AggTestConfig withCheckAggregator(Consumer<Aggregator> checkAggregator) {
return new AggTestConfig(
query,
builder,
maxBuckets,
splitLeavesIntoSeparateAggregators,
shouldBeCached,
incrementalReduce,
useLogDocMergePolicy,
testReductionCancellation,
checkAggregator,
fieldTypes
);
}
Expand Down