|
30 | 30 | import org.elasticsearch.index.IndexSettings;
|
31 | 31 | import org.elasticsearch.index.IndexVersion;
|
32 | 32 | import org.elasticsearch.index.mapper.DateFieldMapper;
|
33 |
| -import org.elasticsearch.index.query.AbstractQueryBuilder; |
34 | 33 | import org.elasticsearch.index.query.BoolQueryBuilder;
|
35 | 34 | import org.elasticsearch.index.query.CoordinatorRewriteContextProvider;
|
| 35 | +import org.elasticsearch.index.query.QueryBuilder; |
36 | 36 | import org.elasticsearch.index.query.RangeQueryBuilder;
|
37 | 37 | import org.elasticsearch.index.query.TermQueryBuilder;
|
38 | 38 | import org.elasticsearch.index.shard.IndexLongFieldRange;
|
39 | 39 | import org.elasticsearch.index.shard.ShardId;
|
40 | 40 | import org.elasticsearch.index.shard.ShardLongFieldRange;
|
41 | 41 | import org.elasticsearch.search.CanMatchShardResponse;
|
| 42 | +import org.elasticsearch.search.aggregations.AggregationBuilder; |
| 43 | +import org.elasticsearch.search.aggregations.bucket.terms.SignificantTermsAggregationBuilder; |
42 | 44 | import org.elasticsearch.search.builder.SearchSourceBuilder;
|
43 | 45 | import org.elasticsearch.search.internal.AliasFilter;
|
44 | 46 | import org.elasticsearch.search.internal.ShardSearchRequest;
|
45 | 47 | import org.elasticsearch.search.sort.MinAndMax;
|
46 | 48 | import org.elasticsearch.search.sort.SortBuilders;
|
47 | 49 | import org.elasticsearch.search.sort.SortOrder;
|
| 50 | +import org.elasticsearch.search.suggest.SuggestBuilder; |
48 | 51 | import org.elasticsearch.test.ESTestCase;
|
49 | 52 | import org.elasticsearch.threadpool.TestThreadPool;
|
50 | 53 | import org.elasticsearch.threadpool.ThreadPool;
|
@@ -497,14 +500,14 @@ public void testCanMatchFilteringOnCoordinatorThatCanBeSkipped() throws Exceptio
|
497 | 500 | regularIndices,
|
498 | 501 | contextProviderBuilder.build(),
|
499 | 502 | queryBuilder,
|
| 503 | + List.of(), |
| 504 | + null, |
500 | 505 | (updatedSearchShardIterators, requests) -> {
|
501 | 506 | List<SearchShardIterator> skippedShards = updatedSearchShardIterators.stream().filter(SearchShardIterator::skip).toList();
|
502 |
| - ; |
503 | 507 |
|
504 | 508 | List<SearchShardIterator> nonSkippedShards = updatedSearchShardIterators.stream()
|
505 | 509 | .filter(searchShardIterator -> searchShardIterator.skip() == false)
|
506 | 510 | .toList();
|
507 |
| - ; |
508 | 511 |
|
509 | 512 | int regularIndexShardCount = (int) updatedSearchShardIterators.stream()
|
510 | 513 | .filter(s -> regularIndices.contains(s.shardId().getIndex()))
|
@@ -568,6 +571,8 @@ public void testCanMatchFilteringOnCoordinatorParsingFails() throws Exception {
|
568 | 571 | regularIndices,
|
569 | 572 | contextProviderBuilder.build(),
|
570 | 573 | queryBuilder,
|
| 574 | + List.of(), |
| 575 | + null, |
571 | 576 | this::assertAllShardsAreQueried
|
572 | 577 | );
|
573 | 578 | }
|
@@ -624,6 +629,99 @@ public void testCanMatchFilteringOnCoordinatorThatCanNotBeSkipped() throws Excep
|
624 | 629 | regularIndices,
|
625 | 630 | contextProviderBuilder.build(),
|
626 | 631 | queryBuilder,
|
| 632 | + List.of(), |
| 633 | + null, |
| 634 | + this::assertAllShardsAreQueried |
| 635 | + ); |
| 636 | + } |
| 637 | + |
| 638 | + public void testCanMatchFilteringOnCoordinator_withSignificantTermsAggregation_withDefaultBackgroundFilter() throws Exception { |
| 639 | + Index index1 = new Index("index1", UUIDs.base64UUID()); |
| 640 | + Index index2 = new Index("index2", UUIDs.base64UUID()); |
| 641 | + Index index3 = new Index("index3", UUIDs.base64UUID()); |
| 642 | + |
| 643 | + StaticCoordinatorRewriteContextProviderBuilder contextProviderBuilder = new StaticCoordinatorRewriteContextProviderBuilder(); |
| 644 | + contextProviderBuilder.addIndexMinMaxTimestamps(index1, DataStream.TIMESTAMP_FIELD_NAME, 0, 999); |
| 645 | + contextProviderBuilder.addIndexMinMaxTimestamps(index2, DataStream.TIMESTAMP_FIELD_NAME, 1000, 1999); |
| 646 | + contextProviderBuilder.addIndexMinMaxTimestamps(index3, DataStream.TIMESTAMP_FIELD_NAME, 2000, 2999); |
| 647 | + |
| 648 | + QueryBuilder query = new BoolQueryBuilder().filter(new RangeQueryBuilder(DataStream.TIMESTAMP_FIELD_NAME).from(2100).to(2200)); |
| 649 | + AggregationBuilder aggregation = new SignificantTermsAggregationBuilder("significant_terms"); |
| 650 | + |
| 651 | + assignShardsAndExecuteCanMatchPhase( |
| 652 | + List.of(), |
| 653 | + List.of(index1, index2, index3), |
| 654 | + contextProviderBuilder.build(), |
| 655 | + query, |
| 656 | + List.of(aggregation), |
| 657 | + null, |
| 658 | + // The default background filter matches the whole index, so all shards must be queried. |
| 659 | + this::assertAllShardsAreQueried |
| 660 | + ); |
| 661 | + } |
| 662 | + |
| 663 | + public void testCanMatchFilteringOnCoordinator_withSignificantTermsAggregation_withBackgroundFilter() throws Exception { |
| 664 | + Index index1 = new Index("index1", UUIDs.base64UUID()); |
| 665 | + Index index2 = new Index("index2", UUIDs.base64UUID()); |
| 666 | + Index index3 = new Index("index3", UUIDs.base64UUID()); |
| 667 | + Index index4 = new Index("index4", UUIDs.base64UUID()); |
| 668 | + |
| 669 | + StaticCoordinatorRewriteContextProviderBuilder contextProviderBuilder = new StaticCoordinatorRewriteContextProviderBuilder(); |
| 670 | + contextProviderBuilder.addIndexMinMaxTimestamps(index1, DataStream.TIMESTAMP_FIELD_NAME, 0, 999); |
| 671 | + contextProviderBuilder.addIndexMinMaxTimestamps(index2, DataStream.TIMESTAMP_FIELD_NAME, 1000, 1999); |
| 672 | + contextProviderBuilder.addIndexMinMaxTimestamps(index3, DataStream.TIMESTAMP_FIELD_NAME, 2000, 2999); |
| 673 | + contextProviderBuilder.addIndexMinMaxTimestamps(index4, DataStream.TIMESTAMP_FIELD_NAME, 3000, 3999); |
| 674 | + |
| 675 | + QueryBuilder query = new BoolQueryBuilder().filter(new RangeQueryBuilder(DataStream.TIMESTAMP_FIELD_NAME).from(3100).to(3200)); |
| 676 | + AggregationBuilder aggregation = new SignificantTermsAggregationBuilder("significant_terms").backgroundFilter( |
| 677 | + new RangeQueryBuilder(DataStream.TIMESTAMP_FIELD_NAME).from(0).to(1999) |
| 678 | + ); |
| 679 | + |
| 680 | + assignShardsAndExecuteCanMatchPhase( |
| 681 | + List.of(), |
| 682 | + List.of(index1, index2, index3), |
| 683 | + contextProviderBuilder.build(), |
| 684 | + query, |
| 685 | + List.of(aggregation), |
| 686 | + null, |
| 687 | + (updatedSearchShardIterators, requests) -> { |
| 688 | + // The search query matches index4, the background query matches index1 and index2, |
| 689 | + // so index3 is the only one that must be skipped. |
| 690 | + for (SearchShardIterator shard : updatedSearchShardIterators) { |
| 691 | + if (shard.shardId().getIndex().getName().equals("index3")) { |
| 692 | + assertTrue(shard.skip()); |
| 693 | + } else { |
| 694 | + assertFalse(shard.skip()); |
| 695 | + } |
| 696 | + } |
| 697 | + } |
| 698 | + ); |
| 699 | + } |
| 700 | + |
| 701 | + public void testCanMatchFilteringOnCoordinator_withSignificantTermsAggregation_withSuggest() throws Exception { |
| 702 | + Index index1 = new Index("index1", UUIDs.base64UUID()); |
| 703 | + Index index2 = new Index("index2", UUIDs.base64UUID()); |
| 704 | + Index index3 = new Index("index3", UUIDs.base64UUID()); |
| 705 | + |
| 706 | + StaticCoordinatorRewriteContextProviderBuilder contextProviderBuilder = new StaticCoordinatorRewriteContextProviderBuilder(); |
| 707 | + contextProviderBuilder.addIndexMinMaxTimestamps(index1, DataStream.TIMESTAMP_FIELD_NAME, 0, 999); |
| 708 | + contextProviderBuilder.addIndexMinMaxTimestamps(index2, DataStream.TIMESTAMP_FIELD_NAME, 1000, 1999); |
| 709 | + contextProviderBuilder.addIndexMinMaxTimestamps(index3, DataStream.TIMESTAMP_FIELD_NAME, 2000, 2999); |
| 710 | + |
| 711 | + QueryBuilder query = new BoolQueryBuilder().filter(new RangeQueryBuilder(DataStream.TIMESTAMP_FIELD_NAME).from(2100).to(2200)); |
| 712 | + AggregationBuilder aggregation = new SignificantTermsAggregationBuilder("significant_terms").backgroundFilter( |
| 713 | + new RangeQueryBuilder(DataStream.TIMESTAMP_FIELD_NAME).from(2000).to(2300) |
| 714 | + ); |
| 715 | + SuggestBuilder suggest = new SuggestBuilder().setGlobalText("test"); |
| 716 | + |
| 717 | + assignShardsAndExecuteCanMatchPhase( |
| 718 | + List.of(), |
| 719 | + List.of(index1, index2, index3), |
| 720 | + contextProviderBuilder.build(), |
| 721 | + query, |
| 722 | + List.of(aggregation), |
| 723 | + suggest, |
| 724 | + // The query and aggregation and match only index3, but suggest should match everything. |
627 | 725 | this::assertAllShardsAreQueried
|
628 | 726 | );
|
629 | 727 | }
|
@@ -669,6 +767,8 @@ public void testCanMatchFilteringOnCoordinatorThatCanBeSkippedTsdb() throws Exce
|
669 | 767 | List.of(),
|
670 | 768 | contextProviderBuilder.build(),
|
671 | 769 | queryBuilder,
|
| 770 | + List.of(), |
| 771 | + null, |
672 | 772 | (updatedSearchShardIterators, requests) -> {
|
673 | 773 | var skippedShards = updatedSearchShardIterators.stream().filter(SearchShardIterator::skip).toList();
|
674 | 774 | var nonSkippedShards = updatedSearchShardIterators.stream()
|
@@ -713,11 +813,13 @@ private void assertAllShardsAreQueried(List<SearchShardIterator> updatedSearchSh
|
713 | 813 | assertThat(requests.size(), equalTo(shardsWithPrimariesAssigned));
|
714 | 814 | }
|
715 | 815 |
|
716 |
| - private <QB extends AbstractQueryBuilder<QB>> void assignShardsAndExecuteCanMatchPhase( |
| 816 | + private void assignShardsAndExecuteCanMatchPhase( |
717 | 817 | List<DataStream> dataStreams,
|
718 | 818 | List<Index> regularIndices,
|
719 | 819 | CoordinatorRewriteContextProvider contextProvider,
|
720 |
| - AbstractQueryBuilder<QB> query, |
| 820 | + QueryBuilder query, |
| 821 | + List<AggregationBuilder> aggregations, |
| 822 | + SuggestBuilder suggest, |
721 | 823 | BiConsumer<List<SearchShardIterator>, List<ShardSearchRequest>> canMatchResultsConsumer
|
722 | 824 | ) throws Exception {
|
723 | 825 | Map<String, Transport.Connection> lookup = new ConcurrentHashMap<>();
|
@@ -764,14 +866,20 @@ private <QB extends AbstractQueryBuilder<QB>> void assignShardsAndExecuteCanMatc
|
764 | 866 | searchRequest.allowPartialSearchResults(true);
|
765 | 867 |
|
766 | 868 | final AliasFilter aliasFilter;
|
767 |
| - if (randomBoolean()) { |
| 869 | + if (aggregations.isEmpty() == false || randomBoolean()) { |
768 | 870 | // Apply the query on the request body
|
769 | 871 | SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource();
|
770 | 872 | searchSourceBuilder.query(query);
|
| 873 | + for (AggregationBuilder aggregation : aggregations) { |
| 874 | + searchSourceBuilder.aggregation(aggregation); |
| 875 | + } |
| 876 | + if (suggest != null) { |
| 877 | + searchSourceBuilder.suggest(suggest); |
| 878 | + } |
771 | 879 | searchRequest.source(searchSourceBuilder);
|
772 | 880 |
|
773 | 881 | // Sometimes apply the same query in the alias filter too
|
774 |
| - aliasFilter = AliasFilter.of(randomBoolean() ? query : null, Strings.EMPTY_ARRAY); |
| 882 | + aliasFilter = AliasFilter.of(aggregations.isEmpty() && randomBoolean() ? query : null, Strings.EMPTY_ARRAY); |
775 | 883 | } else {
|
776 | 884 | // Apply the query as an alias filter
|
777 | 885 | aliasFilter = AliasFilter.of(query, Strings.EMPTY_ARRAY);
|
|
0 commit comments