You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by jb...@apache.org on 2023/09/19 15:19:47 UTC

[solr] branch branch_9x updated: SOLR-16931: ReRankScaler explain breaks with debug=true and in distributed mode (#1936) (#1937)

This is an automated email from the ASF dual-hosted git repository.

jbernste pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/branch_9x by this push:
     new 3e9c9df8ddb  SOLR-16931: ReRankScaler explain breaks with debug=true and in distributed mode (#1936) (#1937)
3e9c9df8ddb is described below

commit 3e9c9df8ddb488c7e6939a9fceaa9d048e24d54b
Author: Joel Bernstein <jb...@apache.org>
AuthorDate: Tue Sep 19 11:19:39 2023 -0400

     SOLR-16931: ReRankScaler explain breaks with debug=true and in distributed mode (#1936) (#1937)
---
 .../solr/handler/component/QueryComponent.java     |  32 ++++++
 .../apache/solr/search/ReRankQParserPlugin.java    |  17 ++++
 .../solr/search/DistributedReRankExplainTest.java  | 109 +++++++++++++++++++++
 .../solr/search/TestReRankQParserPlugin.java       |   2 +-
 4 files changed, 159 insertions(+), 1 deletion(-)

diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
index a2b46a30d46..e8457df3e08 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
@@ -88,6 +88,7 @@ import org.apache.solr.search.QueryParsing;
 import org.apache.solr.search.QueryResult;
 import org.apache.solr.search.QueryUtils;
 import org.apache.solr.search.RankQuery;
+import org.apache.solr.search.ReRankQParserPlugin;
 import org.apache.solr.search.ReturnFields;
 import org.apache.solr.search.SolrIndexSearcher;
 import org.apache.solr.search.SolrReturnFields;
@@ -757,6 +758,7 @@ public class QueryComponent extends SearchComponent {
     boolean distribSinglePass = rb.req.getParams().getBool(ShardParams.DISTRIB_SINGLE_PASS, false);
 
     if (distribSinglePass
+        || singlePassExplain(rb.req.getParams())
         || (fields != null
             && fields.wantsField(keyFieldName)
             && fields.getRequestedFieldNames() != null
@@ -838,6 +840,36 @@ public class QueryComponent extends SearchComponent {
     rb.addRequest(this, sreq);
   }
 
+  private boolean singlePassExplain(SolrParams params) {
+
+    /*
+     * Currently there is only one explain that requires a single pass
+     * and that is the reRank when scaling is used.
+     */
+
+    String rankQuery = params.get(CommonParams.RQ);
+    if (rankQuery != null) {
+      if (rankQuery.contains(ReRankQParserPlugin.RERANK_MAIN_SCALE)
+          || rankQuery.contains(ReRankQParserPlugin.RERANK_SCALE)) {
+        boolean debugQuery = params.getBool(CommonParams.DEBUG_QUERY, false);
+        if (debugQuery) {
+          return true;
+        } else {
+          String[] debugParams = params.getParams(CommonParams.DEBUG);
+          if (debugParams != null) {
+            for (String debugParam : debugParams) {
+              if (debugParam.equals("true")) {
+                return true;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return false;
+  }
+
   protected boolean addFL(StringBuilder fl, String field, boolean additionalAdded) {
     if (additionalAdded) fl.append(",");
     fl.append(field);
diff --git a/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java
index 2ae72837218..e9597c3dd86 100644
--- a/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java
@@ -17,6 +17,7 @@
 package org.apache.solr.search;
 
 import java.io.IOException;
+import java.lang.invoke.MethodHandles;
 import org.apache.lucene.search.MatchAllDocsQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryRescorer;
@@ -25,6 +26,8 @@ import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.request.SolrQueryRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /*
  *
@@ -50,6 +53,7 @@ public class ReRankQParserPlugin extends QParserPlugin {
 
   public static final String RERANK_SCALE = "reRankScale";
   public static final String RERANK_MAIN_SCALE = "reRankMainScale";
+  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
   @Override
   public QParser createParser(
@@ -85,6 +89,19 @@ public class ReRankQParserPlugin extends QParserPlugin {
       String mainScale = localParams.get(RERANK_MAIN_SCALE);
       String reRankScale = localParams.get(RERANK_SCALE);
       boolean debugQuery = params.getBool(CommonParams.DEBUG_QUERY, false);
+
+      if (!debugQuery) {
+        String[] debugParams = params.getParams(CommonParams.DEBUG);
+        if (debugParams != null) {
+          for (String debugParam : debugParams) {
+            if ("true".equals(debugParam)) {
+              debugQuery = true;
+              break;
+            }
+          }
+        }
+      }
+
       double reRankScaleWeight = reRankWeight;
 
       ReRankScaler reRankScaler =
diff --git a/solr/core/src/test/org/apache/solr/search/DistributedReRankExplainTest.java b/solr/core/src/test/org/apache/solr/search/DistributedReRankExplainTest.java
new file mode 100644
index 00000000000..defe6fef4ff
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/search/DistributedReRankExplainTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+import java.lang.invoke.MethodHandles;
+import java.util.Map;
+import java.util.Random;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SolrTestCaseJ4.SuppressSSL
+public class DistributedReRankExplainTest extends SolrCloudTestCase {
+
+  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  private static final int numShards = 2;
+  private static final String COLLECTIONORALIAS = "collection1";
+
+  private static final int TIMEOUT = DEFAULT_TIMEOUT;
+  private static final String id = "id";
+
+  private static boolean useAlias;
+
+  @BeforeClass
+  public static void setupCluster() throws Exception {
+    System.setProperty("managed.schema.mutable", "true");
+    String collection = COLLECTIONORALIAS;
+    configureCluster(2)
+        .addConfig(
+            "conf1", TEST_PATH().resolve("configsets").resolve("cloud-managed").resolve("conf"))
+        .configure();
+    CollectionAdminRequest.createCollection(collection, "conf1", 2, 1)
+        .setPerReplicaState(SolrCloudTestCase.USE_PER_REPLICA_STATE)
+        .process(cluster.getSolrClient());
+
+    cluster.waitForActiveCollection(collection, 2, 2);
+  }
+
+  @Test
+  public void testReRankExplain() throws Exception {
+    CloudSolrClient client = cluster.getSolrClient();
+    UpdateRequest updateRequest = new UpdateRequest();
+    for (int i = 0; i < 100; i++) {
+      SolrInputDocument doc = new SolrInputDocument();
+      doc.addField(CommonParams.ID, Integer.toString(i));
+      doc.addField("test_s", "hello");
+      updateRequest.add(doc);
+    }
+    updateRequest.process(client, COLLECTIONORALIAS);
+    client.commit(COLLECTIONORALIAS);
+
+    String[] debugParams = {CommonParams.DEBUG, CommonParams.DEBUG_QUERY};
+    Random random = random();
+    ModifiableSolrParams solrParams = new ModifiableSolrParams();
+    String reRank = "{!rerank reRankDocs=10 reRankMainScale=0-10 reRankQuery='test_s:hello'}";
+    solrParams
+        .add("q", "test_s:hello")
+        .add(debugParams[random.nextInt(2)], "true")
+        .add(CommonParams.RQ, reRank);
+    QueryRequest queryRequest = new QueryRequest(solrParams);
+    QueryResponse queryResponse = queryRequest.process(client, COLLECTIONORALIAS);
+    Map<String, Object> debug = queryResponse.getDebugMap();
+    assertNotNull(debug);
+    String explain = debug.get("explain").toString();
+    assertTrue(
+        explain.contains("5.0101576 = combined scaled first and unscaled second pass score "));
+
+    solrParams = new ModifiableSolrParams();
+    reRank = "{!rerank reRankDocs=10 reRankScale=0-10 reRankQuery='test_s:hello'}";
+    solrParams
+        .add("q", "test_s:hello")
+        .add(debugParams[random.nextInt(2)], "true")
+        .add(CommonParams.RQ, reRank);
+    queryRequest = new QueryRequest(solrParams);
+    queryResponse = queryRequest.process(client, COLLECTIONORALIAS);
+    debug = queryResponse.getDebugMap();
+    assertNotNull(debug);
+    explain = debug.get("explain").toString();
+    assertTrue(
+        explain.contains("10.005078 = combined unscaled first and scaled second pass score "));
+  }
+}
diff --git a/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java b/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java
index f551ba82fca..5d769c4e57f 100644
--- a/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java
+++ b/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java
@@ -1522,7 +1522,7 @@ public class TestReRankQParserPlugin extends SolrTestCaseJ4 {
     params.add("start", "0");
     params.add("rows", "6");
     params.add("df", "text");
-    params.add("debugQuery", "true");
+    params.add("debug", "true");
     assertQ(
         req(params),
         "*[count(//doc)=6]",