Skip to content

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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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.common.params.CombinerParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.search.facet.FacetModule;

/**
* 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 {

/**
* 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 new ResponseBuilder(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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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.search.combine;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.Query;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CombinerParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.component.ShardDoc;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.search.QueryResult;
import org.apache.solr.search.SolrIndexSearcher;

/**
* The QueryAndResponseCombiner class is an abstract base class for combining query results and
* shard documents. It provides a framework for different algorithms to be implemented for merging
* ranked lists and shard documents.
*/
public abstract class QueryAndResponseCombiner {

public abstract void init(NamedList<?> args);

/**
* Combines multiple ranked lists into a single QueryResult.
*
* @param rankedLists a list of ranked lists to be combined
* @param solrParams params to be used when provided at query time
* @return a new QueryResult containing the combined results
* @throws IllegalArgumentException if the input list is empty
*/
public abstract QueryResult combine(List<QueryResult> rankedLists, SolrParams solrParams);

/**
* Combines shard documents based on the provided map.
*
* @param shardDocMap a map where keys represent shard IDs and values are lists of ShardDocs for
* each shard
* @param solrParams params to be used when provided at query time
* @return a combined list of ShardDocs from all shards
*/
public abstract List<ShardDoc> combine(
Map<String, List<ShardDoc>> shardDocMap, SolrParams solrParams);

/**
* Retrieves a list of explanations for the given queries and results.
*
* @param queryKeys the keys associated with the queries
* @param queries the list of queries for which explanations are requested
* @param queryResult the list of QueryResult corresponding to each query
* @param searcher the SolrIndexSearcher used to perform the search
* @param schema the IndexSchema used to interpret the search results
* @param solrParams params to be used when provided at query time
* @return a list of explanations for the given queries and results
* @throws IOException if an I/O error occurs during the explanation retrieval process
*/
public abstract NamedList<Explanation> getExplanations(
Copy link
Contributor

Choose a reason for hiding this comment

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

Please implement support for debug as well

String[] queryKeys,
List<Query> queries,
List<QueryResult> queryResult,
SolrIndexSearcher searcher,
IndexSchema schema,
SolrParams solrParams)
throws IOException;

/**
* Retrieves an implementation of the QueryAndResponseCombiner based on the specified algorithm.
*
* @param requestParams the SolrParams containing the request parameters, including the combiner
* algorithm.
* @param combiners The already initialised map of QueryAndResponseCombiner
* @return an instance of QueryAndResponseCombiner corresponding to the specified algorithm.
* @throws SolrException if an unknown combiner algorithm is specified.
*/
public static QueryAndResponseCombiner getImplementation(
SolrParams requestParams, Map<String, QueryAndResponseCombiner> combiners) {
String algorithm =
requestParams.get(CombinerParams.COMBINER_ALGORITHM, CombinerParams.DEFAULT_COMBINER);
if (combiners.containsKey(algorithm)) {
return combiners.get(algorithm);
}
throw new SolrException(
SolrException.ErrorCode.BAD_REQUEST, "Unknown Combining algorithm: " + algorithm);
}
}
Loading