-
Notifications
You must be signed in to change notification settings - Fork 787
SOLR-17319 : Combined Query Feature for Multi Query Execution #3418
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
base: main
Are you sure you want to change the base?
Changes from 50 commits
bf3cd5d
182bec9
b884f0e
29e8aea
c113799
3600ed3
9b0c76e
a841bc7
91f8e09
cace1f7
299db43
840070e
d2feefc
89f63a9
d821abb
8041d66
397dbb3
d8b5588
ec0b9cb
d6fd190
86933bc
b164979
85f2cf9
a4a26aa
7fe997c
bcd1c3b
787a016
7e0727c
4dcbb57
8a65023
006b8c2
771089b
460e8cd
ac85d2f
7b0593c
c03c0f7
a52dd22
195f3f1
c1f5501
3649d3e
4eedbed
0990e7f
14ff5e1
bd637b7
2958599
c3e44c3
e2dfcef
d4b34fc
3fe93b8
f23cceb
6419a07
a560899
ae84ef3
1083fdd
be428f0
5b487c2
18e8518
f08f75e
1ed538a
2b7342b
aa0c23a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package org.apache.solr.handler.component; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import org.apache.solr.request.SolrQueryRequest; | ||
| import org.apache.solr.response.SolrQueryResponse; | ||
|
|
||
| /** | ||
| * The CombinedQueryResponseBuilder class extends the ResponseBuilder class and is responsible for | ||
| * building a combined response for multiple SearchComponent objects. It orchestrates the process of | ||
| * constructing the SolrQueryResponse by aggregating results from various components. | ||
| */ | ||
| public class CombinedQueryResponseBuilder extends ResponseBuilder { | ||
|
|
||
| public final List<ResponseBuilder> responseBuilders = new ArrayList<>(); | ||
|
|
||
| /** | ||
| * Constructs a CombinedQueryResponseBuilder instance. | ||
| * | ||
| * @param req the SolrQueryRequest object containing the query parameters and context. | ||
| * @param rsp the SolrQueryResponse object to which the combined results will be added. | ||
| * @param components a list of SearchComponent objects that will be used to build the response. | ||
| */ | ||
| public CombinedQueryResponseBuilder( | ||
| SolrQueryRequest req, SolrQueryResponse rsp, List<SearchComponent> components) { | ||
| super(req, rsp, components); | ||
| } | ||
|
|
||
| /** | ||
| * Propagates all the properties from parent ResponseBuilder to the all the children which are | ||
| * being set later after the CombinedQueryComponent is prepared. | ||
| */ | ||
| public final void propagate() { | ||
| responseBuilders.forEach( | ||
| thisRb -> { | ||
| thisRb.setNeedDocSet(isNeedDocSet()); | ||
| thisRb.setNeedDocList(isNeedDocList()); | ||
| thisRb.doFacets = doFacets; | ||
| thisRb.doHighlights = doHighlights; | ||
| thisRb.doExpand = doExpand; | ||
| thisRb.doTerms = doTerms; | ||
| thisRb.doStats = doStats; | ||
| thisRb.setDistribStatsDisabled(isDistribStatsDisabled()); | ||
| }); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package org.apache.solr.handler.component; | ||
|
|
||
| import java.lang.invoke.MethodHandles; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import org.apache.solr.common.params.CombinerParams; | ||
| import org.apache.solr.request.SolrQueryRequest; | ||
| import org.apache.solr.response.SolrQueryResponse; | ||
| import org.apache.solr.search.facet.FacetModule; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| /** | ||
| * The CombinedQuerySearchHandler class extends the SearchHandler and provides custom behavior for | ||
| * handling combined queries. It overrides methods to create a response builder based on the {@link | ||
| * CombinerParams#COMBINER} parameter and to define the default components included in the search | ||
| * configuration. | ||
| */ | ||
| public class CombinedQuerySearchHandler extends SearchHandler { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); | ||
|
|
||
| /** | ||
| * Overrides the default response builder creation method. This method checks if the {@link | ||
| * CombinerParams#COMBINER} parameter is set to true in the request. If it is, it returns an | ||
| * instance of {@link CombinedQueryResponseBuilder}, otherwise, it returns an instance of {@link | ||
| * ResponseBuilder}. | ||
| * | ||
| * @param req the SolrQueryRequest object | ||
| * @param rsp the SolrQueryResponse object | ||
| * @param components the list of SearchComponent objects | ||
| * @return the appropriate ResponseBuilder instance based on the CombinerParams.COMBINER parameter | ||
| */ | ||
| @Override | ||
| protected ResponseBuilder newResponseBuilder( | ||
| SolrQueryRequest req, SolrQueryResponse rsp, List<SearchComponent> components) { | ||
| if (req.getParams().getBool(CombinerParams.COMBINER, false)) { | ||
| return new CombinedQueryResponseBuilder(req, rsp, components); | ||
| } | ||
| return super.newResponseBuilder(req, rsp, components); | ||
| } | ||
|
|
||
| /** | ||
| * Overrides the default components and returns a list of component names that are included in the | ||
| * default configuration. | ||
| * | ||
| * @return a list of component names | ||
| */ | ||
| @Override | ||
| @SuppressWarnings("unchecked") | ||
| protected List<String> getDefaultComponents() { | ||
| List<String> names = new ArrayList<>(9); | ||
| names.add(CombinedQueryComponent.COMPONENT_NAME); | ||
| names.add(FacetComponent.COMPONENT_NAME); | ||
| names.add(FacetModule.COMPONENT_NAME); | ||
| names.add(MoreLikeThisComponent.COMPONENT_NAME); | ||
| names.add(HighlightComponent.COMPONENT_NAME); | ||
| names.add(StatsComponent.COMPONENT_NAME); | ||
| names.add(DebugComponent.COMPONENT_NAME); | ||
| names.add(ExpandComponent.COMPONENT_NAME); | ||
| names.add(TermsComponent.COMPONENT_NAME); | ||
| return names; | ||
| } | ||
|
|
||
| @Override | ||
| protected void postPrepareComponents(ResponseBuilder rb) { | ||
| super.postPrepareComponents(rb); | ||
| // propagate the CombinedQueryResponseBuilder's state to all subBuilders after prepare | ||
| if (rb instanceof CombinedQueryResponseBuilder crb) { | ||
| crb.propagate(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |
| import java.lang.invoke.MethodHandles; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
| import java.util.concurrent.BlockingQueue; | ||
| import java.util.concurrent.CompletableFuture; | ||
|
|
@@ -31,6 +32,7 @@ | |
| import java.util.concurrent.TimeUnit; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import net.jcip.annotations.NotThreadSafe; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.apache.solr.client.solrj.SolrRequest; | ||
| import org.apache.solr.client.solrj.SolrResponse; | ||
| import org.apache.solr.client.solrj.impl.Http2SolrClient; | ||
|
|
@@ -404,6 +406,9 @@ public void cancelAll() { | |
|
|
||
| @Override | ||
| public void prepDistributed(ResponseBuilder rb) { | ||
| if (rb.isForcedDistrib()) { | ||
| forceDistributed(rb); | ||
| } | ||
| final SolrQueryRequest req = rb.req; | ||
| final SolrParams params = req.getParams(); | ||
| final String shards = params.get(ShardParams.SHARDS); | ||
|
|
@@ -500,6 +505,28 @@ public void prepDistributed(ResponseBuilder rb) { | |
| } | ||
| } | ||
|
|
||
| private static void forceDistributed(ResponseBuilder rb) { | ||
| SolrQueryRequest req = rb.req; | ||
| ModifiableSolrParams solrParams = new ModifiableSolrParams(req.getParams()); | ||
| solrParams.set("shortCircuit", false); | ||
| req.setParams(solrParams); | ||
| if (req.getHttpSolrCall() != null | ||
| && StringUtils.isEmpty(req.getParams().get(ShardParams.SHARDS))) { | ||
ercsonusharma marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| String scheme = req.getHttpSolrCall().getReq().getScheme(); | ||
| String host = req.getHttpSolrCall().getReq().getServerName(); | ||
| int port = req.getHttpSolrCall().getReq().getServerPort(); | ||
| String context = req.getHttpSolrCall().getReq().getContextPath(); | ||
| String core = req.getCore().getName(); | ||
| String localShardUrl = | ||
| String.format(Locale.ROOT, "%s://%s:%d%s/%s", scheme, host, port, context, core); | ||
| solrParams.set(ShardParams.SHARDS, localShardUrl); | ||
| req.setParams(solrParams); | ||
| return; | ||
| } | ||
|
Comment on lines
513
to
525
Contributor
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 part looks suspicious to me; so shortCircuit=false isn't enough? Did you construct this based on seeing similar code elsewhere (where?) to create a shards URL?
Author
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. No, shortCircuit=false is not enough as ShardHandler also needs the
Contributor
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. Ah. I see so it needs to happen somewhere, and you've put it here. It feels out of place in this method, however. Based on what you showed me, it could be in HttpShardHandler where StandaloneReplicaSource.Builder is used.
Contributor
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. Also, the URL core construction here seems like it should be a utility method on HttpSolrCall |
||
| throw new SolrException( | ||
| SolrException.ErrorCode.BAD_REQUEST, "Force Distributed cannot be enabled"); | ||
| } | ||
|
|
||
| private static String createSliceShardsStr(final List<String> shardUrls) { | ||
| return String.join("|", shardUrls); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.