@@ -298,6 +298,7 @@ public void testMatchNoDocsQuery() throws Exception {
298298 createIndex ,
299299 (InternalTerms <?, ?> result ) -> { assertEquals (0 , result .getBuckets ().size ()); },
300300 new AggTestConfig (aggregationBuilder , fieldType ).withQuery (new MatchNoDocsQuery ())
301+ .withCheckAggregator (checkTopLevelAggregatorNoRewrites (TermsAggregatorFactory .ExecutionMode .MAP ))
301302 );
302303
303304 debugTestCase (aggregationBuilder , new MatchNoDocsQuery (), createIndex , (result , impl , debug ) -> {
@@ -337,7 +338,6 @@ public void testStringShardZeroMinDocCount() throws IOException {
337338 .executionHint (executionMode .toString ())
338339 .size (2 )
339340 .minDocCount (0 )
340- .executionHint ("map" )
341341 .excludeDeletedDocs (true )
342342 .order (BucketOrder .key (true ));
343343
@@ -360,7 +360,80 @@ public void testStringShardZeroMinDocCount() throws IOException {
360360 assertEquals ("b" , result .getBuckets ().get (1 ).getKeyAsString ());
361361 }
362362 assertEquals (0L , result .getBuckets ().get (1 ).getDocCount ());
363- }, new AggTestConfig (aggregationBuilder , fieldType ).withQuery (new TermQuery (new Term ("string" , "e" ))));
363+ },
364+ new AggTestConfig (aggregationBuilder , fieldType ).withQuery (new TermQuery (new Term ("string" , "e" )))
365+ .withCheckAggregator (checkTopLevelAggregatorNoRewrites (executionMode ))
366+ );
367+ }
368+
369+ {
370+ boolean delete = randomBoolean ();
371+ // force single shard/segment
372+ testCase (iw -> {
373+ // force single shard/segment
374+ iw .addDocuments (
375+ Arrays .asList (doc (fieldType , "a" ), doc (fieldType , "c" , "d" ), doc (fieldType , "b" , "d" ), doc (fieldType , "b" ))
376+ );
377+ if (delete ) {
378+ iw .deleteDocuments (new TermQuery (new Term ("string" , "b" )));
379+ }
380+ }, (InternalTerms <?, ?> result ) -> {
381+ assertEquals (2 , result .getBuckets ().size ());
382+ assertEquals ("a" , result .getBuckets ().get (0 ).getKeyAsString ());
383+ assertEquals (0L , result .getBuckets ().get (0 ).getDocCount ());
384+ if (delete ) {
385+ assertEquals ("c" , result .getBuckets ().get (1 ).getKeyAsString ());
386+ } else {
387+ assertEquals ("b" , result .getBuckets ().get (1 ).getKeyAsString ());
388+ }
389+ assertEquals (0L , result .getBuckets ().get (1 ).getDocCount ());
390+ },
391+ new AggTestConfig (aggregationBuilder , fieldType ).withQuery (new TermQuery (new Term ("string" , "e" )))
392+ .withCheckAggregator (checkTopLevelAggregatorNoRewrites (executionMode ))
393+ );
394+ }
395+ }
396+ }
397+
398+ /**
399+ * Asserts that sane output for {@code min_doc_count: 0} when the top level
400+ * query is {@code match_none}. Especially important is that we respect the
401+ * execution hint in this case. It's a lot faster to collect {@code min_doc_count: 0}
402+ * via ordinals.
403+ */
404+ public void testStringZeroMinDocCountMatchNone () throws IOException {
405+ MappedFieldType fieldType = new KeywordFieldMapper .KeywordFieldType ("string" , true , true , Collections .emptyMap ());
406+ for (TermsAggregatorFactory .ExecutionMode executionMode : TermsAggregatorFactory .ExecutionMode .values ()) {
407+ TermsAggregationBuilder aggregationBuilder = new TermsAggregationBuilder ("_name" ).field ("string" )
408+ .executionHint (executionMode .toString ())
409+ .size (2 )
410+ .minDocCount (0 )
411+ .excludeDeletedDocs (true )
412+ .order (BucketOrder .key (true ));
413+
414+ {
415+ boolean delete = randomBoolean ();
416+ // force single shard/segment
417+ testCase (iw -> {
418+ // force single shard/segment
419+ iw .addDocuments (Arrays .asList (doc (fieldType , "a" ), doc (fieldType , "b" ), doc (fieldType , "c" ), doc (fieldType , "d" )));
420+ if (delete ) {
421+ iw .deleteDocuments (new TermQuery (new Term ("string" , "b" )));
422+ }
423+ }, (InternalTerms <?, ?> result ) -> {
424+ assertEquals (2 , result .getBuckets ().size ());
425+ assertEquals ("a" , result .getBuckets ().get (0 ).getKeyAsString ());
426+ assertEquals (0L , result .getBuckets ().get (0 ).getDocCount ());
427+ if (delete ) {
428+ assertEquals ("c" , result .getBuckets ().get (1 ).getKeyAsString ());
429+ } else {
430+ assertEquals ("b" , result .getBuckets ().get (1 ).getKeyAsString ());
431+ }
432+ assertEquals (0L , result .getBuckets ().get (1 ).getDocCount ());
433+ },
434+ new AggTestConfig (aggregationBuilder , fieldType ).withQuery (new MatchNoDocsQuery ())
435+ .withCheckAggregator (checkTopLevelAggregatorNoRewrites (executionMode ))
436+ );
364437 }
365438
366439 {
@@ -384,7 +457,10 @@ public void testStringShardZeroMinDocCount() throws IOException {
384457 assertEquals ("b" , result .getBuckets ().get (1 ).getKeyAsString ());
385458 }
386459 assertEquals (0L , result .getBuckets ().get (1 ).getDocCount ());
387- }, new AggTestConfig (aggregationBuilder , fieldType ).withQuery (new TermQuery (new Term ("string" , "e" ))));
460+ },
461+ new AggTestConfig (aggregationBuilder , fieldType ).withQuery (new MatchNoDocsQuery ())
462+ .withCheckAggregator (checkTopLevelAggregatorNoRewrites (executionMode ))
463+ );
388464 }
389465 }
390466 }
@@ -2279,4 +2355,11 @@ protected List<ObjectMapper> objectMappers() {
22792355 private String randomHint () {
22802356 return randomFrom (TermsAggregatorFactory .ExecutionMode .values ()).toString ();
22812357 }
2358+
2359+ private Consumer <Aggregator > checkTopLevelAggregatorNoRewrites (TermsAggregatorFactory .ExecutionMode executionMode ) {
2360+ return switch (executionMode ) {
2361+ case MAP -> a -> assertThat (a , instanceOf (MapStringTermsAggregator .class ));
2362+ case GLOBAL_ORDINALS -> a -> assertThat (a , instanceOf (GlobalOrdinalsStringTermsAggregator .class ));
2363+ };
2364+ }
22822365}
0 commit comments