ercsonusharma commented on code in PR #3418: URL: https://github.com/apache/solr/pull/3418#discussion_r2282674479
########## solr/core/src/java/org/apache/solr/handler/component/CombinedQuerySearchHandler.java: ########## @@ -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 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); Review Comment: I don't think so. In the case of SearchHandler, we are using `QueryComponent` as the first component. ########## solr/core/src/test/org/apache/solr/search/combine/ReciprocalRankFusionTest.java: ########## @@ -0,0 +1,138 @@ +/* + * 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 static org.apache.solr.common.params.CombinerParams.COMBINER_RRF_K; +import static org.apache.solr.common.params.CombinerParams.RECIPROCAL_RANK_FUSION; + +import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.lucene.search.TotalHits; +import org.apache.solr.SolrTestCaseJ4; +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.search.DocSlice; +import org.apache.solr.search.QueryResult; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * The ReciprocalRankFusionTest class is a unit test suite for the {@link ReciprocalRankFusion} + * class. It verifies the correctness of the fusion algorithm and its supporting methods. + */ +@ThreadLeakScope(ThreadLeakScope.Scope.NONE) +public class ReciprocalRankFusionTest extends SolrTestCaseJ4 { + + public static ReciprocalRankFusion reciprocalRankFusion; + + /** + * Initializes the test environment by setting up the {@link ReciprocalRankFusion} instance with + * specific parameters. + */ + @BeforeClass + public static void beforeClass() { + NamedList<?> args = new NamedList<>(Map.of("k", "20")); + reciprocalRankFusion = new ReciprocalRankFusion(); + reciprocalRankFusion.init(args); + } + + /** Tests the functionality of combining using RRF across local search indices. */ + @Test + public void testSearcherCombine() { + List<QueryResult> rankedList = getQueryResults(); + SolrParams solrParams = params(COMBINER_RRF_K, "10"); + QueryResult result = reciprocalRankFusion.combine(rankedList, solrParams); + assertEquals(20, reciprocalRankFusion.getK()); + assertEquals(3, result.getDocList().size()); + } + + private static List<QueryResult> getQueryResults() { + QueryResult r1 = new QueryResult(); + r1.setDocList( + new DocSlice( + 0, + 2, + new int[] {1, 2}, + new float[] {0.67f, 0, 62f}, Review Comment: typo. corrected. ########## solr/solr-ref-guide/modules/query-guide/pages/json-combined-query-dsl.adoc: ########## @@ -0,0 +1,113 @@ += JSON Combined Query DSL +:tabs-sync-option: +// 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. + +The Combined Query feature aims to execute multiple queries of multiple kinds across multiple shards of a collection and combine their result basis an algorithm (like Reciprocal Rank Fusion). +It is extending JSON Query DSL ultimately enabling Hybrid Search. + +[NOTE] +==== +This feature is currently unsupported for non-distributed and grouping query. Using Cursors is not advisable, as it may produce inconsistent results. +==== + +== Query DSL Structure +The query structure is similar to JSON Query DSL except for how multiple queries are defined along with their parameters. + +* Multiple queries can be defined under the `queries` key by providing their name with the same syntax as a single query is defined with the key `query`. +* In addition to the other supported parameters, there are several parameters which can be defined under `params` key as below: +`combiner.enable` | Default: `false`:: + Enables the combined query mode when set to `true`. +`combiner.query`:: + The list of queries to be executed as defined in the `queries` key. Example: `["query1", "query2"]` +`combiner.algorithm` | Default: `rrf`:: + The algorithm to be used for combining the results. Reciprocal Rank Fusion (RRF) is the in-built fusion algorithm. + Any other algorithm can be configured using xref:json-combined-query-dsl.adoc#combiner-algorithm-plugin[plugin]. +`combiner.rrf.k` | Default: `60`:: + The k parameter in the RRF algorithm. + +=== Example + +Below is a sample JSON query payload: + +``` +{ + "queries": { + "lexical1": { + "lucene": { + "query": "title:sales" + } + }, + "lexical2": { + "lucene": { + "query": "title:report" + } + }, + "vector": { + "knn": { + "f": "vector", + "topK" :5, + "query": "[0.1,-0.34,0.89,0.02]" + } + } + }, + "limit": 5, + "fields": ["id", "score", "title"], + "params": { + "combiner": true, Review Comment: typo. corrected. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
