- Notifications
You must be signed in to change notification settings - Fork 25.6k
Add sub_searches to the search endpoint #96224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e867b60 ef1a959 3c2d6bd 97f465d 541b6c1 e7971e1 3bb28ce 17311de 56a5602 3dc0b8b fdc27a7 188c6f6 03568c1 649e778 e0e4ee2 ad95da3 70f673c 26f2883 5315d0e e0ec23e e18cf29 8fa9c52 807f654 9a06051 0d6dbeb 9424ef6 6c9e87b b7c75e1 a32b488 3dfae23 baef214 e32d50c 2776684 fe637c9 f467433 b60cd61 3735fb3 841b0bb c74e6fc 26c680b c7b8d31 f43555c f93fb93 b396353 9a80229 a63a47d 1e626f7 b5e5a9e 0739193 143357d 1235aa3 f5801b1 81b677c 68f8911 a3682e1 babafdf ccd63b1 c5d5e76 fb2efeb d0f3c3e 4bcde34 b2b9c96 43070f6 d552c3c a8aae3a b3afe73 9987b05 b969149 5969916 7c2bf13 c7d924d c248c33 7a20d0a e0aa9bf 79811bd 82d5be6 754fa18 60e0bfe b78b395 faeb437 087467d fb44b52 3e075f4 ce83df4 70b5dbd 60f1367 3a790b4 e6f8591 f89e085 7289e37 48d6f5f 6c991bb f4655c1 1b98e56 403185f File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| pr: 96224 | ||
| summary: Add multiple queries for ranking to the search endpoint | ||
| area: Ranking | ||
| type: enhancement | ||
| issues: [] | ||
| highlight: | ||
| title: Add multiple queries for ranking to the search endpoint | ||
| body: "The search endpoint adds a new top-level element called `sub_searches`. \ | ||
| This top-level element is a list of searches used for ranking where each \ | ||
| \"sub search\" is executed independently. The `sub_searches` element is \ | ||
| used instead of `query` to allow a search using ranking to execute \ | ||
| multiple queries. The `sub_searches` and `query` elements cannot be used \ | ||
| together." | ||
| notable: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -104,7 +104,9 @@ private void innerRun() throws Exception { | |
| final SearchPhaseController.ReducedQueryPhase reducedQueryPhase = resultConsumer.reduce(); | ||
| // Usually when there is a single shard, we force the search type QUERY_THEN_FETCH. But when there's kNN, we might | ||
| // still use DFS_QUERY_THEN_FETCH, which does not perform the "query and fetch" optimization during the query phase. | ||
| final boolean queryAndFetchOptimization = queryResults.length() == 1 && context.getRequest().hasKnnSearch() == false; | ||
| final boolean queryAndFetchOptimization = queryResults.length() == 1 | ||
| && context.getRequest().hasKnnSearch() == false | ||
| && reducedQueryPhase.rankCoordinatorContext() == null; | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this specifically required by the support for multiple queries or was it missing before as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is specifically required for multiple queries. It wasn't missing before. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think what confuses me is that we don't look for the multiple queries but rather for the rank coordinator context. This could use a comment to explain why, or maybe the conditional could be shared in a single place, assuming it is always exactly the same. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edit: Oops meant this comment for something else. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realized I didn't answer this correctly. This is required specifically for ranking. If we have a single query and multiple knn searches, those become a boolean query and it's fine to shortcut. | ||
| final Runnable finishPhase = () -> moveToNextPhase( | ||
| queryResults, | ||
| reducedQueryPhase, | ||
| | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -77,6 +77,7 @@ | |
| import org.elasticsearch.search.aggregations.support.AggregationContext; | ||
| import org.elasticsearch.search.aggregations.support.AggregationContext.ProductionAggregationContext; | ||
| import org.elasticsearch.search.builder.SearchSourceBuilder; | ||
| import org.elasticsearch.search.builder.SubSearchSourceBuilder; | ||
| import org.elasticsearch.search.collapse.CollapseContext; | ||
| import org.elasticsearch.search.dfs.DfsPhase; | ||
| import org.elasticsearch.search.dfs.DfsSearchResult; | ||
| | @@ -626,7 +627,7 @@ private SearchPhaseResult executeQueryPhase(ShardSearchRequest request, SearchSh | |
| } finally { | ||
| tracer.stopTrace(); | ||
| } | ||
| if (request.numberOfShards() == 1) { | ||
| if (request.numberOfShards() == 1 && (request.source() == null || request.source().rankBuilder() == null)) { | ||
javanna marked this conversation as resolved. Show resolved Hide resolved | ||
| // we already have query results, but we can run fetch at the same time | ||
| context.addFetchResult(); | ||
| return executeFetchPhase(readerContext, context, afterQueryTime); | ||
| | @@ -992,13 +993,6 @@ protected SearchContext createContext( | |
| if (context.size() == -1) { | ||
| context.size(DEFAULT_SIZE); | ||
| } | ||
| if (request.rankQueryBuilders().isEmpty() == false) { | ||
| List<Query> rankQueries = new ArrayList<>(); | ||
| for (QueryBuilder queryBuilder : request.rankQueryBuilders()) { | ||
| rankQueries.add(queryBuilder.toQuery(context.getSearchExecutionContext())); | ||
| } | ||
| context.rankShardContext(request.source().rankBuilder().buildRankShardContext(rankQueries, context.from())); | ||
| } | ||
| context.setTask(task); | ||
| | ||
| context.preProcess(); | ||
| | @@ -1166,7 +1160,7 @@ private void processFailure(ReaderContext context, Exception exc) { | |
| } | ||
| } | ||
| | ||
| private void parseSource(DefaultSearchContext context, SearchSourceBuilder source, boolean includeAggregations) { | ||
| private void parseSource(DefaultSearchContext context, SearchSourceBuilder source, boolean includeAggregations) throws IOException { | ||
| // nothing to parse... | ||
| if (source == null) { | ||
| return; | ||
| | @@ -1176,9 +1170,10 @@ private void parseSource(DefaultSearchContext context, SearchSourceBuilder sourc | |
| context.from(source.from()); | ||
| context.size(source.size()); | ||
| Map<String, InnerHitContextBuilder> innerHitBuilders = new HashMap<>(); | ||
| if (source.query() != null) { | ||
| InnerHitContextBuilder.extractInnerHits(source.query(), innerHitBuilders); | ||
| context.parsedQuery(searchExecutionContext.toQuery(source.query())); | ||
| QueryBuilder query = source.query(); | ||
| if (query != null) { | ||
| InnerHitContextBuilder.extractInnerHits(query, innerHitBuilders); | ||
| context.parsedQuery(searchExecutionContext.toQuery(query)); | ||
| } | ||
| if (source.postFilter() != null) { | ||
| InnerHitContextBuilder.extractInnerHits(source.postFilter(), innerHitBuilders); | ||
| | @@ -1374,6 +1369,14 @@ private void parseSource(DefaultSearchContext context, SearchSourceBuilder sourc | |
| final CollapseContext collapseContext = source.collapse().build(searchExecutionContext); | ||
| context.collapse(collapseContext); | ||
| } | ||
| | ||
| if (source.rankBuilder() != null) { | ||
| List<Query> queries = new ArrayList<>(); | ||
| for (SubSearchSourceBuilder subSearchSourceBuilder : source.subSearches()) { | ||
| queries.add(subSearchSourceBuilder.toSearchQuery(context.getSearchExecutionContext())); | ||
| } | ||
| context.rankShardContext(source.rankBuilder().buildRankShardContext(queries, context.from())); | ||
| } | ||
| } | ||
| | ||
| /** | ||
| | @@ -1623,14 +1626,12 @@ private static boolean canMatchAfterRewrite(final ShardSearchRequest request, fi | |
| @SuppressWarnings("unchecked") | ||
| public static boolean queryStillMatchesAfterRewrite(ShardSearchRequest request, QueryRewriteContext context) throws IOException { | ||
| Rewriteable.rewrite(request.getRewriteable(), context, false); | ||
| final boolean aliasFilterCanMatch = request.getAliasFilter().getQueryBuilder() instanceof MatchNoneQueryBuilder == false; | ||
| final boolean canMatch; | ||
| boolean canMatch = request.getAliasFilter().getQueryBuilder() instanceof MatchNoneQueryBuilder == false; | ||
| if (canRewriteToMatchNone(request.source())) { | ||
| QueryBuilder queryBuilder = request.source().query(); | ||
| canMatch = aliasFilterCanMatch && queryBuilder instanceof MatchNoneQueryBuilder == false; | ||
| } else { | ||
| // null query means match_all | ||
| canMatch = aliasFilterCanMatch; | ||
| canMatch &= request.source() | ||
| .subSearches() | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will subsearches here already contain the knn queries too? I think so, and that should not be an issue, but I wanted to double check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there should never be a knn search here because can_match only works with query_then_fetch, but not dfs_query_Then_fetch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh good point. maybe that is something that we need to discuss changing. | ||
| .stream() | ||
| .anyMatch(sqwb -> sqwb.getQueryBuilder() instanceof MatchNoneQueryBuilder == false); | ||
| } | ||
| return canMatch; | ||
| } | ||
| | @@ -1641,7 +1642,11 @@ public static boolean queryStillMatchesAfterRewrite(ShardSearchRequest request, | |
| * a global aggregation is part of this request or if there is a suggest builder present. | ||
| */ | ||
| public static boolean canRewriteToMatchNone(SearchSourceBuilder source) { | ||
| if (source == null || source.query() == null || source.query() instanceof MatchAllQueryBuilder || source.suggest() != null) { | ||
| if (source == null || source.suggest() != null) { | ||
| return false; | ||
| } | ||
| if (source.subSearches().isEmpty() | ||
| || source.subSearches().stream().anyMatch(sqwb -> sqwb.getQueryBuilder() instanceof MatchAllQueryBuilder)) { | ||
| return false; | ||
| } | ||
| AggregatorFactories.Builder aggregations = source.aggregations(); | ||
| | ||
Uh oh!
There was an error while loading. Please reload this page.