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

dsmiley 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 6d20a11  SOLR-12901: make hl.method=unified the default (#579)
6d20a11 is described below

commit 6d20a119aa558e5de2cf75716bb5afb440995321
Author: David Smiley <[email protected]>
AuthorDate: Fri Feb 4 16:13:49 2022 -0500

    SOLR-12901: make hl.method=unified the default (#579)
    
    * handle highlighting no fields; an edge-case
    * fixed minor assertion failure about a RTimer state that could be wrong if 
the request is re-used
    * did not switch ClusteringComponent; it will take more care, can happen 
later
    * custom SolrHighlighter impls have to be chosen with hl.method=original
    
    * Remove PostingsSolrHighlighter (deprecated), missed from SOLR-13138
---
 solr/CHANGES.txt                                   |   2 +
 .../solr/handler/component/HighlightComponent.java |  35 ++--
 .../solr/highlight/PostingsSolrHighlighter.java    |  71 --------
 .../solr/highlight/UnifiedSolrHighlighter.java     |   7 +-
 .../solr/highlight/FastVectorHighlighterTest.java  |   9 +-
 .../solr/highlight/HighlighterConfigTest.java      |   8 +-
 .../org/apache/solr/highlight/HighlighterTest.java | 201 +++++++--------------
 .../org/apache/solr/request/TestWriterPerf.java    |   2 +-
 .../solr/search/TestSurroundQueryParser.java       |   8 +-
 .../handler/clustering/ClusteringComponent.java    |  39 ++--
 .../solr/configsets/_default/conf/solrconfig.xml   |   2 +
 .../conf/solrconfig.xml                            |   2 +
 solr/solr-ref-guide/src/highlighting.adoc          |  17 +-
 .../src/major-changes-in-solr-9.adoc               |   3 +
 14 files changed, 138 insertions(+), 268 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index d4366b9..edf4737 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -540,6 +540,8 @@ and each individual module's jar will be included in its 
directory's lib/ folder
 
 * SOLR-15777: Forbid useDocValuesAsStored for ICUCollationField (warn for 
luceneMatchVersion < 9.0.0). (Michael Gibney)
 
+* SOLR-12901: Highlighting: hl.method=unified is the new default. (David 
Smiley)
+
 Bug Fixes
 ---------------------
 * SOLR-15849: Fix the connection reset problem caused by the incorrect use of 
4LW with \n when monitoring zooKeeper status (Fa Ming).
diff --git 
a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java 
b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
index ba42018..340bb6a 100644
--- 
a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
+++ 
b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
@@ -16,6 +16,9 @@
  */
 package org.apache.solr.handler.component;
 
+import static java.util.stream.Collectors.toMap;
+
+import com.google.common.base.MoreObjects;
 import java.io.IOException;
 import java.lang.reflect.Array;
 import java.util.Collections;
@@ -23,8 +26,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.function.Function;
 import java.util.stream.Stream;
-
-import com.google.common.base.MoreObjects;
 import org.apache.lucene.search.Query;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.HighlightParams;
@@ -45,11 +46,9 @@ import org.apache.solr.util.SolrPluginUtils;
 import org.apache.solr.util.plugin.PluginInfoInitialized;
 import org.apache.solr.util.plugin.SolrCoreAware;
 
-import static java.util.stream.Collectors.toMap;
-
 /**
- * TODO!
- *
+ * Highlights query words in the search results.
+ * See the <a href="https://solr.apache.org/guide/highlighting.html";>ref 
guide</a>.
  *
  * @since solr 1.3
  */
@@ -80,10 +79,10 @@ public class HighlightComponent extends SearchComponent 
implements PluginInfoIni
 
   public static final String COMPONENT_NAME = "highlight";
 
-  private PluginInfo info = PluginInfo.EMPTY_INFO;
+  protected PluginInfo info = PluginInfo.EMPTY_INFO;
 
   // TODO lets restructure the abstractions/relationships
-  private SolrHighlighter solrConfigHighlighter;
+  protected SolrHighlighter solrConfigHighlighter;
 
   @Override
   public void init(PluginInfo info) {
@@ -165,27 +164,23 @@ public class HighlightComponent extends SearchComponent 
implements PluginInfoIni
     }
   }
 
+  /** The highlighter given the param {@link HighlightParams#METHOD}. Never 
returns null. */
   public SolrHighlighter getHighlighter(SolrParams params) {
-    HighlightMethod method = 
HighlightMethod.parse(params.get(HighlightParams.METHOD));
-    if (method == null) {
-      return solrConfigHighlighter;
-    }
+    HighlightMethod method = 
HighlightMethod.parse(params.get(HighlightParams.METHOD, "unified"));
 
     switch (method) {
       case UNIFIED:
         if (solrConfigHighlighter instanceof UnifiedSolrHighlighter) {
           return solrConfigHighlighter;
         }
-        return new UnifiedSolrHighlighter(); // TODO cache one?
+        return new UnifiedSolrHighlighter(); // cheap
       case FAST_VECTOR: // fall-through
       case ORIGINAL:
-        if (solrConfigHighlighter instanceof DefaultSolrHighlighter) {
-          return solrConfigHighlighter;
-        } else {
-          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
-              "In order to use " + HighlightParams.METHOD + "=" + 
method.getMethodName() + " the configured" +
-                  " highlighter in solrconfig must be " + 
DefaultSolrHighlighter.class);
-        }
+        // The configured highlighter might not actually be the original 
highlighter if
+        //  someone specified class= something custom.
+        // Perhaps we shouldn't even support custom SolrHighlighter impls, and 
instead
+        //  we ask users to subclass HighlightComponent instead?
+        return solrConfigHighlighter;
       default: throw new AssertionError();
     }
   }
diff --git 
a/solr/core/src/java/org/apache/solr/highlight/PostingsSolrHighlighter.java 
b/solr/core/src/java/org/apache/solr/highlight/PostingsSolrHighlighter.java
deleted file mode 100644
index 2e1c483..0000000
--- a/solr/core/src/java/org/apache/solr/highlight/PostingsSolrHighlighter.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.highlight;
-
-import java.lang.invoke.MethodHandles;
-
-import org.apache.lucene.search.uhighlight.UnifiedHighlighter;
-import org.apache.solr.common.params.HighlightParams;
-import org.apache.solr.common.params.ModifiableSolrParams;
-import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.core.PluginInfo;
-import org.apache.solr.request.LocalSolrQueryRequest;
-import org.apache.solr.request.SolrQueryRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** 
- * Highlighter impl that uses {@link UnifiedHighlighter} configured to operate 
as it's ancestor/predecessor, the
- * {code PostingsHighlighter}.
- *
- * @deprecated Use {@link UnifiedSolrHighlighter} instead
- */
-@Deprecated
-public class PostingsSolrHighlighter extends UnifiedSolrHighlighter {
-  private static final Logger log = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  @Override
-  public void init(PluginInfo info) {
-    log.warn("The PostingsSolrHighlighter is deprecated; use the 
UnifiedSolrHighlighter instead.");
-    super.init(info);
-  }
-
-  @Override
-  protected UnifiedHighlighter getHighlighter(SolrQueryRequest req) {
-    // Adjust the highlight parameters to match what the old 
PostingsHighlighter had.
-    ModifiableSolrParams invariants = new ModifiableSolrParams();
-    invariants.set(HighlightParams.OFFSET_SOURCE, "POSTINGS");
-    invariants.set(HighlightParams.FIELD_MATCH, true);
-    invariants.set(HighlightParams.USE_PHRASE_HIGHLIGHTER, false);
-    invariants.set(HighlightParams.FRAGSIZE, -1);
-
-    ModifiableSolrParams defaults = new ModifiableSolrParams();
-    defaults.set(HighlightParams.DEFAULT_SUMMARY, true);
-    defaults.set(HighlightParams.TAG_ELLIPSIS, "... ");
-
-    SolrParams newParams = SolrParams.wrapDefaults(
-        invariants,// this takes precedence
-        SolrParams.wrapDefaults(
-            req.getParams(), // then this (original)
-            defaults // finally our defaults
-        )
-    );
-    try (LocalSolrQueryRequest fakeReq = new 
LocalSolrQueryRequest(req.getCore(), newParams)) {
-      return super.getHighlighter(fakeReq);
-    }
-  }
-}
diff --git 
a/solr/core/src/java/org/apache/solr/highlight/UnifiedSolrHighlighter.java 
b/solr/core/src/java/org/apache/solr/highlight/UnifiedSolrHighlighter.java
index 46f8255..4c56200 100644
--- a/solr/core/src/java/org/apache/solr/highlight/UnifiedSolrHighlighter.java
+++ b/solr/core/src/java/org/apache/solr/highlight/UnifiedSolrHighlighter.java
@@ -18,6 +18,7 @@ package org.apache.solr.highlight;
 
 import java.io.IOException;
 import java.text.BreakIterator;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Locale;
@@ -145,7 +146,10 @@ public class UnifiedSolrHighlighter extends 
SolrHighlighter implements PluginInf
     }
 
     UnifiedHighlighter highlighter = getHighlighter(req);
-    Map<String, String[]> snippets = highlighter.highlightFields(fieldNames, 
query, docIDs, maxPassages);
+    Map<String, String[]> snippets =
+        fieldNames.length == 0
+            ? Collections.emptyMap()
+            : highlighter.highlightFields(fieldNames, query, docIDs, 
maxPassages);
     return encodeSnippets(keys, fieldNames, snippets);
   }
 
@@ -247,6 +251,7 @@ public class UnifiedSolrHighlighter extends SolrHighlighter 
implements PluginInf
         timerTree = new RTimerTree(); // since null checks are annoying
       }
       loadFieldValuesTimer = timerTree.sub("loadFieldValues"); // we assume a 
new timer, state of STARTED
+      loadFieldValuesTimer.resume(); // ensure state is STARTED (some obscure 
test / use-case)
       loadFieldValuesTimer.pause(); // state of PAUSED now with about zero 
time. Will fail if state isn't STARTED.
     }
 
diff --git 
a/solr/core/src/test/org/apache/solr/highlight/FastVectorHighlighterTest.java 
b/solr/core/src/test/org/apache/solr/highlight/FastVectorHighlighterTest.java
index 5f9b916..e4975b0 100644
--- 
a/solr/core/src/test/org/apache/solr/highlight/FastVectorHighlighterTest.java
+++ 
b/solr/core/src/test/org/apache/solr/highlight/FastVectorHighlighterTest.java
@@ -17,12 +17,11 @@
 package org.apache.solr.highlight;
 
 import java.util.HashMap;
-
 import java.util.Map;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.params.HighlightParams;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.handler.component.HighlightComponent;
-import org.apache.solr.util.TestHarness;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -78,15 +77,13 @@ public class FastVectorHighlighterTest extends 
SolrTestCaseJ4 {
     } else {
       args.put("hl.method", "fastVector"); // the new way
     }
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "",0,200,args);
     
     assertU(adoc("tv_text", "basic fast vector highlighter test", 
                  "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("tv_text:vector"),
+        req(new MapSolrParams(args), "q", "tv_text:vector"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='tv_text']/str[.='basic fast 
<fvpre>vector</em> highlighter test']"
             );
@@ -94,6 +91,6 @@ public class FastVectorHighlighterTest extends SolrTestCaseJ4 
{
 
   private static DefaultSolrHighlighter getHighlighter() {
     var hl = (HighlightComponent) 
h.getCore().getSearchComponents().get(HighlightComponent.COMPONENT_NAME);
-    return (DefaultSolrHighlighter) hl.getHighlighter(new 
MapSolrParams(Map.of()));
+    return (DefaultSolrHighlighter) hl.getHighlighter(new 
MapSolrParams(Map.of(HighlightParams.METHOD, "fastVector")));
   }
 }
diff --git 
a/solr/core/src/test/org/apache/solr/highlight/HighlighterConfigTest.java 
b/solr/core/src/test/org/apache/solr/highlight/HighlighterConfigTest.java
index 047a67c..ec9ae9e 100644
--- a/solr/core/src/test/org/apache/solr/highlight/HighlighterConfigTest.java
+++ b/solr/core/src/test/org/apache/solr/highlight/HighlighterConfigTest.java
@@ -23,7 +23,6 @@ import java.util.Map;
 import org.apache.solr.common.params.MapSolrParams;
 import org.apache.solr.handler.component.HighlightComponent;
 import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.util.TestHarness;
 import org.junit.BeforeClass;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -60,23 +59,22 @@ public class HighlighterConfigTest extends SolrTestCaseJ4 {
     // check to see that doHighlight is called from the DummyHighlighter
     HashMap<String,String> args = new HashMap<>();
     args.put("hl", "true");
+    args.put("hl.method", "original");
     args.put("df", "t_text");
     args.put("hl.fl", "");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
 
     assertU(adoc("t_text", "a long day's night", "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("long"),
+            req(new MapSolrParams(args), "q", "long"),
             "//lst[@name='highlighting']/str[@name='dummy']"
             );
   }
 
   private static SolrHighlighter getHighlighter() {
     var hl = (HighlightComponent) 
h.getCore().getSearchComponents().get(HighlightComponent.COMPONENT_NAME);
-    return hl.getHighlighter(new MapSolrParams(Map.of()));
+    return hl.getHighlighter(new MapSolrParams(Map.of("hl.method", 
"original")));
   }
 }
 
diff --git a/solr/core/src/test/org/apache/solr/highlight/HighlighterTest.java 
b/solr/core/src/test/org/apache/solr/highlight/HighlighterTest.java
index 9ec2cf9..979f189 100644
--- a/solr/core/src/test/org/apache/solr/highlight/HighlighterTest.java
+++ b/solr/core/src/test/org/apache/solr/highlight/HighlighterTest.java
@@ -29,21 +29,20 @@ import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.TokenStream;
 import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.queries.payloads.SpanPayloadCheckQuery;
 import org.apache.lucene.queries.spans.SpanTermQuery;
 import org.apache.lucene.search.Query;
-import org.apache.lucene.queries.payloads.SpanPayloadCheckQuery;
 import org.apache.lucene.util.BytesRef;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.params.HighlightParams;
 import org.apache.solr.common.params.MapSolrParams;
+import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.handler.component.HighlightComponent;
 import org.apache.solr.handler.component.ResponseBuilder;
 import org.apache.solr.handler.component.SearchComponent;
-import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.search.DocSet;
-import org.apache.solr.util.TestHarness;
 import org.junit.After;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -101,8 +100,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put(HighlightParams.FRAGSIZE, String.valueOf(40));
     args.put(HighlightParams.MERGE_CONTIGUOUS_FRAGMENTS, "true");
     args.put(HighlightParams.METHOD, "original"); // test works; no complaints
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
+    
     String input = "this is some long text.  It has the word long in many 
places.  In fact, it has long on some different fragments.  " +
             "Let us see what happens to long in this case.";
     String gold = "this is some <em>long</em> text.  It has the word 
<em>long</em> in many places.  In fact, it has <em>long</em> on some different 
fragments.  " +
@@ -111,7 +109,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("Merge Contiguous",
-            sumLRF.makeRequest("t_text:long"),
+        req(args, "q", "t_text:long"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='t_text']/str[.='" + gold + "']"
             );
@@ -120,17 +118,16 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("Merge Contiguous",
-            sumLRF.makeRequest("t_text:long"),
+        req(args, "q", "t_text:long"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='t_text']/str[.='" + gold + "']"
             );
 
     args.put(HighlightParams.MERGE_CONTIGUOUS_FRAGMENTS, "false");
     args.put("f.t_text." + HighlightParams.MERGE_CONTIGUOUS_FRAGMENTS, 
"false");
-    sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
+    
     assertQ("Merge Contiguous",
-        sumLRF.makeRequest("t_text:long"),
+        req(args, "q", "t_text:long"),
         "//lst[@name='highlighting']/lst[@name='1']",
         "//lst[@name='1']/arr[@name='t_text']/str[.='this is some 
<em>long</em> text.  It has']",
         "//lst[@name='1']/arr[@name='t_text']/str[.=' the word <em>long</em> 
in many places.  In fact, it has']",
@@ -147,15 +144,13 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl", "true");
     args.put("hl.fl", "tv_text");
     args.put("hl.snippets", "2");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "",0,200,args);
     
     assertU(adoc("tv_text", LONG_TEXT, 
                  "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("tv_text:long"),
+            req(args, "q", "tv_text:long"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='tv_text']/str[.='a <em>long</em> days 
night this should be a piece of text which']",
             "//arr[@name='tv_text']/str[.=' <em>long</em> fragments.']"
@@ -167,16 +162,15 @@ public class HighlighterTest extends SolrTestCaseJ4 {
 
     HashMap<String,String> args = new HashMap<>();
     args.put("hl", "true");
+    args.put("hl.method", "original");
     args.put("hl.fl", "tv_no_off_text");
-
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory("", 0, 200, 
args);
-
+    
     assertU(adoc("tv_no_off_text", "Crackerjack Cameron", "id", "1"));
     assertU(commit());
     assertU(optimize());
 
     assertQ("Fields with term vectors switched on but no offsets should be 
correctly highlighted",
-            sumLRF.makeRequest("tv_no_off_text:cameron"),
+        req(args, "q", "tv_no_off_text:cameron"),
             "//arr[@name='tv_no_off_text']/str[.='Crackerjack 
<em>Cameron</em>']");
 
   }
@@ -214,8 +208,6 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl", "true");
     args.put("hl.fl", "tv_mv_text");
     args.put("hl.snippets", "2");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "",0,200,args);
     
     assertU(adoc("tv_mv_text", LONG_TEXT, 
                  "tv_mv_text", LONG_TEXT, 
@@ -223,7 +215,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("tv_mv_text:long"),
+        req(args, "q", "tv_mv_text:long"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='tv_mv_text']/str[.='a <em>long</em> 
days night this should be a piece of text which']",
             "//arr[@name='tv_mv_text']/str[.=' <em>long</em> fragments.']"
@@ -241,8 +233,6 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl", "true");
     args.put("hl.fl", "tv_mv_text");
     args.put("hl.snippets", "2");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "",0,200,args);
 
     String shortText = "short";
     assertU(adoc("tv_mv_text", shortText,
@@ -251,7 +241,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("tv_mv_text:long"),
+        req(args, "q", "tv_mv_text:long"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='tv_mv_text']/str[.='a <em>long</em> 
days night this should be a piece of text which']",
             "//arr[@name='tv_mv_text']/str[.=' <em>long</em> fragments.']"
@@ -267,21 +257,20 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.fl", "tv_text");
     args.put("qf", "tv_text");
     args.put("q.alt", "*:*");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "/dismax",0,200,args);
-    
+    args.put("defType", "dismax");
+
     assertU(adoc("tv_text", "a long day's night", "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-        sumLRF.makeRequest("long"),
+        req(args, "q", "long"),
         "//lst[@name='highlighting']/lst[@name='1']",
         "//lst[@name='1']/arr[@name='tv_text']/str"
     );
     
     // try the same thing without a q param
     assertQ("Should not explode...", // q.alt should return everything
-        sumLRF.makeRequest( new String[] { null } ), // empty query
+        req(args), // empty query
         "//result[@numFound='1']"
         );
   }
@@ -294,8 +283,6 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl", "true");
     args.put("hl.fl", "textgap");
     args.put("df", "textgap");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     assertU(adoc("textgap", "first entry hasnt queryword",
         "textgap", "second entry has queryword long",
@@ -303,7 +290,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("long"),
+            req(args, "q", "long"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='textgap']/str"
             );
@@ -316,8 +303,6 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl", "true");
     args.put("hl.fl", "textgap");
     args.put("df", "textgap");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-        "", 0, 200, args);
     
     assertU(adoc("textgap", "first entry has one word foo", 
         "textgap", "second entry has both words foo bar",
@@ -325,7 +310,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("Best fragment summarization",
-        sumLRF.makeRequest("foo bar"),
+        req(args, "q", "foo bar"),
         "//lst[@name='highlighting']/lst[@name='1']",
         "//lst[@name='1']/arr[@name='textgap']/str[.=\'second entry has both 
words <em>foo</em> <em>bar</em>\']"
     );
@@ -355,14 +340,12 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl", "true");
     args.put("df", "t_text");
     args.put("hl.fl", "");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     assertU(adoc("t_text", "a long day's night", "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-        sumLRF.makeRequest("long"),
+        req(args, "q", "long"),
         "//lst[@name='highlighting']/lst[@name='1']",
         "//lst[@name='1']/arr[@name='t_text']/str"
     );
@@ -377,14 +360,12 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     HashMap<String,String> args = new HashMap<>();
     args.put("hl", "false");
     args.put("hl.fl", "t_text");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     assertU(adoc("t_text", "a long day's night", "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("t_text:long"), 
"not(//lst[@name='highlighting'])");
+            req(args, "q", "t_text:long"), "not(//lst[@name='highlighting'])");
 
   }
 
@@ -395,15 +376,13 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     HashMap<String,String> args = new HashMap<>();
     args.put("hl", "true");
     args.put("hl.fl", "t_text tv_text");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     assertU(adoc("t_text", "a long day's night", "id", "1",
                  "tv_text", "a long night's day"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("t_text:long"),
+            req(args, "q", "t_text:long"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='t_text']/str",
             "//lst[@name='1']/arr[@name='tv_text']/str"
@@ -421,12 +400,10 @@ public class HighlighterTest extends SolrTestCaseJ4 {
      HashMap<String,String> args = new HashMap<>();
      args.put("hl", "true");
      args.put("hl.fl", "t_text1 t_text2");
-     
-     TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-           "", 0, 200, args);
+
      // default should highlight both random and words in both fields
      assertQ("Test Default",
-           sumLRF.makeRequest("t_text1:random OR t_text2:words"),
+           req(args, "q", "t_text1:random OR t_text2:words"),
            "//lst[@name='highlighting']/lst[@name='1']",
            "//lst[@name='1']/arr[@name='t_text1']/str[.='<em>random</em> 
<em>words</em> for highlighting tests']",
            "//lst[@name='1']/arr[@name='t_text2']/str[.='more <em>random</em> 
<em>words</em> for second field']"
@@ -434,10 +411,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
      
      // requireFieldMatch=true - highlighting should only occur if term 
matched in that field
      args.put("hl.requireFieldMatch", "true");
-     sumLRF = h.getRequestFactory(
-           "", 0, 200, args);
      assertQ("Test RequireFieldMatch",
-         sumLRF.makeRequest("t_text1:random OR t_text2:words"),
+         req(args, "q", "t_text1:random OR t_text2:words"),
          "//lst[@name='highlighting']/lst[@name='1']",
          "//lst[@name='1']/arr[@name='t_text1']/str[.='<em>random</em> words 
for highlighting tests']",
          "//lst[@name='1']/arr[@name='t_text2']/str[.='more random 
<em>words</em> for second field']"
@@ -448,10 +423,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
          "t_text2", "more random words for second field"));
      assertU(delI("1"));
      assertU(commit());
-     sumLRF = h.getRequestFactory(
-           "", 0, 200, args);
      assertQ("Test RequireFieldMatch on un-optimized index",
-           sumLRF.makeRequest("t_text1:random OR t_text2:words"),
+           req(args, "q", "t_text1:random OR t_text2:words"),
            "//lst[@name='highlighting']/lst[@name='2']",
            "//lst[@name='2']/arr[@name='t_text1']/str[.='<em>random</em> words 
for highlighting tests']",
            "//lst[@name='2']/arr[@name='t_text2']/str[.='more random 
<em>words</em> for second field']"
@@ -467,14 +440,12 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.fl", "t_text");
     args.put("hl.simple.pre","<B>");
     args.put("hl.simple.post", "</B>");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     assertU(adoc("t_text", "a long days night", "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-        sumLRF.makeRequest("t_text:long"),
+        req(args, "q", "t_text:long"),
         "//lst[@name='highlighting']/lst[@name='1']",
         "//lst[@name='1']/arr[@name='t_text']/str[.='a <B>long</B> days 
night']"
     );
@@ -482,10 +453,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     // test a per-field override
     args.put("f.t_text.hl.simple.pre", "<I>");
     args.put("f.t_text.hl.simple.post", "</I>");
-    sumLRF = h.getRequestFactory(
-          "", 0, 200, args);
     assertQ("Basic summarization",
-          sumLRF.makeRequest("t_text:long"),
+          req(args, "q", "t_text:long"),
           "//lst[@name='highlighting']/lst[@name='1']",
           "//lst[@name='1']/arr[@name='t_text']/str[.='a <I>long</I> days 
night']"
           );
@@ -498,8 +467,6 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     HashMap<String,String> args = new HashMap<>();
     args.put("hl", "true");
     args.put("hl.fl", "tv_text");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
 
     String text = 
@@ -508,7 +475,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("tv_text:dir"),
+            req(args, "q", "tv_text:dir"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='tv_text']/str"
             );
@@ -522,29 +489,25 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.snippets", "10");
     final String field = random().nextBoolean() ? "t_text" : "tv_text";
     args.put("hl.fl", field);
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
 
     assertU(adoc(field, LONG_TEXT, "id", "1"));
     assertU(commit());
 
     assertQ("token at start of text",
-            sumLRF.makeRequest(field + ":disjoint"),
+            req(args, "q", field + ":disjoint"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[count(str)=1]"
             );
     args.put("hl.maxAnalyzedChars", "20");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("token at end of text",
-        sumLRF.makeRequest(field + ":disjoint"),
+        req(args, "q", field + ":disjoint"),
         "//lst[@name='highlighting']/lst[@name='1']",
         "//lst[@name='1'][not(*)]"
     );
     args.put("hl.maxAnalyzedChars", "-1");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("token at start of text",
-        sumLRF.makeRequest(field + ":disjoint"),
+        req(args, "q", field + ":disjoint"),
         "//lst[@name='highlighting']/lst[@name='1']",
         "//lst[@name='1']/arr[count(str)=1]"
     );
@@ -583,8 +546,6 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.fragmenter", "regex");
     args.put("hl.regex.pattern", "[-\\w ,\"']{20,200}");
     args.put("hl.regex.slop", ".9");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     String t = "This is an example of a sentence. Another example \"sentence\" 
with " +
       "special characters\nand a line-break! Miscellaneous character like ^ 
are " +
@@ -594,7 +555,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
     assertQ("regex fragmenter",
-            sumLRF.makeRequest("t_text:example"),
+        req(args, "q", "t_text:example"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//arr/str[.='This is an <em>example</em> of a sentence']",
             "//arr/str[.='. Another <em>example</em> \"sentence\" with special 
characters\nand a line-break']",
@@ -603,9 +564,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
             );
     // try with some punctuation included
     args.put("hl.regex.pattern", "[-\\w ,^/\\n\"']{20,200}");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("regex fragmenter 2",
-            sumLRF.makeRequest("t_text:example"),
+            req(args, "q", "t_text:example"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//arr/str[.='This is an <em>example</em> of a sentence']",
             "//arr/str[.='. Another <em>example</em> \"sentence\" with special 
characters\nand a line-break']",
@@ -625,35 +585,29 @@ public class HighlighterTest extends SolrTestCaseJ4 {
      HashMap<String,String> args = new HashMap<>();
      args.put("hl", "true");
      args.put("hl.fl", "tv_text");
-     TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-       "", 0, 200, args);
      assertQ("Basic summarization",
-           sumLRF.makeRequest("tv_text:long"),
+           req(args, "q", "tv_text:long"),
            "//lst[@name='highlighting']/lst[@name='1']",
            "//lst[@name='1']/arr[@name='tv_text']/str[.='a <em>long</em> days 
night this should be a piece of text which']"
            );
      
      // 25
      args.put("hl.fragsize","25");
-     sumLRF = h.getRequestFactory(
-           "", 0, 200, args);
      assertQ("Basic summarization",
-           sumLRF.makeRequest("tv_text:long"),
+         req(args, "q", "tv_text:long"),
            "//lst[@name='highlighting']/lst[@name='1']",
            "//lst[@name='1']/arr[@name='tv_text']/str[.='a <em>long</em> days 
night']"
            );
      
      // 0 - NullFragmenter
      args.put("hl.fragsize","0");
-     sumLRF = h.getRequestFactory(
-           "", 0, 200, args);
      assertQ("Basic summarization",
-           sumLRF.makeRequest("tv_text:long"),
+         req(args, "q", "tv_text:long"),
            "//lst[@name='highlighting']/lst[@name='1']",
            "//lst[@name='1']/arr[@name='tv_text']/str[.='a <em>long</em> days 
night this should be a piece of text which is is is is is is is is is is is is 
is is is is is is is is is is is is isis is is is is is is is is is is is is is 
is is is is is is is is is is is is is is is is is is is is is is is is is is 
is is is is is is is is is is is is is is is is is is is is is is is is is is 
is is is is is is is is is sufficiently lengthly to produce multiple fragments 
which are not concat [...]
            );
   }
-  
+
   @Test
   public void testAlternateSummary() {
      //long document
@@ -669,21 +623,18 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl", "true");
     args.put("hl.fragsize","0");
     args.put("hl.fl", "t_text");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
 
     // no alternate
     assertQ("Alternate summarization",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=0]"
             );
 
     // with an alternate
     args.put("hl.alternateField", "foo_t");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("Alternate summarization",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='hi']"
             );
@@ -691,9 +642,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     // with an alternate + max length
     args.put("hl.alternateField", "t_text");
     args.put("hl.maxAlternateFieldLength", "15");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("Alternate summarization",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='a piece 
of text']"
             );
@@ -701,9 +651,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     // with a non-existing alternate field + max length
     args.put("hl.alternateField", "NonExistingField");
     args.put("hl.maxAlternateFieldLength", "15");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("Alternate summarization",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='a piece 
of text']"
             );
@@ -729,27 +678,23 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.simple.post", "</simplepost>");
     args.put("hl.alternateField", "tv_text");
     args.put("hl.maxAlternateFieldLength", "39");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     assertQ("Alternate summarization with highlighting",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='<simplepre>keyword</simplepost>
 is only here, tv_text']"
             );
 
     // Query on other field than hl or alternate. Still we get the 
hightlighted snippet from alternate
     assertQ("Alternate summarization with highlighting, query other field",
-            sumLRF.makeRequest("other_t:keyword"),
+        req(args, "q", "other_t:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='<simplepre>keyword</simplepost>
 is only here, tv_text']"
             );
 
     // With hl.requireFieldMatch, will not highlight but fall back to 
plain-text alternate
     args.put("hl.requireFieldMatch", "true");
-    sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     assertQ("Alternate summarization with highlighting, requireFieldMatch",
-            sumLRF.makeRequest("other_t:keyword"),
+        req(args, "q", "other_t:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='keyword 
is only here, tv_text alternate']"
             );
@@ -760,9 +705,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.remove("hl.alternateField");
     args.put("f.t_text.hl.alternateField", "tv_text");
     args.put("f.t_text.hl.maxAlternateFieldLength", "0");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("Alternate summarization with highlighting",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='<simplepre>keyword</simplepost>
 is only here, tv_text alternate field']"
             );
@@ -772,18 +716,16 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.tag.pre", "<fvhpre>");
     args.put("hl.tag.post", "</fvhpost>");
     args.put("f.t_text.hl.maxAlternateFieldLength", "18");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("Alternate summarization with highlighting using FVH",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
         
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='<fvhpre>keyword</fvhpost>
 is only here']"
             );
 
     // Prove it is possible to turn off highlighting of alternate field
     args.put("hl.highlightAlternate", "false");
-    sumLRF = h.getRequestFactory("", 0, 200, args);
     assertQ("Alternate summarization without highlighting",
-            sumLRF.makeRequest("tv_text:keyword"),
+        req(args, "q", "tv_text:keyword"),
             "//lst[@name='highlighting']/lst[@name='1' and count(*)=1]",
             
"//lst[@name='highlighting']/lst[@name='1']/arr[@name='t_text']/str[.='keyword 
is only he']"
             );
@@ -798,9 +740,6 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.snippets", "10");
     args.put("hl.usePhraseHighlighter", "false");
 
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
-
     // String borrowed from Lucene's HighlighterTest
     String t = "This piece of text refers to Kennedy at the beginning then has 
a longer piece of text that is very long in the middle and finally ends with 
another reference to Kennedy";
     
@@ -815,13 +754,13 @@ public class HighlighterTest extends SolrTestCaseJ4 {
   
     // check if old functionality is still the same
     assertQ("Phrase highlighting - old",
-        sumLRF.makeRequest("t_text:\"text refers\""),
+        req(args, "q", "t_text:\"text refers\""),
         "//lst[@name='highlighting']/lst[@name='1']",
         oldHighlight1, oldHighlight2, oldHighlight3
         );
 
     assertQ("Phrase highlighting - old",
-        sumLRF.makeRequest("t_text:text refers"),
+        req(args, "q", "t_text:text refers"),
         "//lst[@name='highlighting']/lst[@name='1']",
         oldHighlight1, oldHighlight2, oldHighlight3
         );
@@ -829,18 +768,16 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     // now check if Lucene-794 highlighting works as expected
     args.put("hl.usePhraseHighlighter", "true");
 
-    sumLRF = h.getRequestFactory("", 0, 200, args);
-    
     // check phrase highlighting
     assertQ("Phrase highlighting - Lucene-794",
-        sumLRF.makeRequest("t_text:\"text refers\""),
+        req(args, "q", "t_text:\"text refers\""),
         "//lst[@name='highlighting']/lst[@name='1']",
         newHighlight1
         );
 
     // non phrase queries should be highlighted as they were before this fix
     assertQ("Phrase highlighting - Lucene-794",
-        sumLRF.makeRequest("t_text:text refers"),
+        req(args, "q", "t_text:text refers"),
         "//lst[@name='highlighting']/lst[@name='1']",
         oldHighlight1, oldHighlight2, oldHighlight3
         );
@@ -863,10 +800,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     assertU(commit());
     assertU(optimize());
 
-    TestHarness.LocalRequestFactory lrf = h.getRequestFactory("", 0,
-        10, args);
-
-    SolrQueryRequest request = lrf.makeRequest("test");
+    SolrQueryRequest request = req(args, "q", "test");
     SolrHighlighter highlighter = getHighlighter();
     List<String> highlightFieldNames = Arrays.asList(highlighter
         .getHighlightFields(null, request, new String[] {}));
@@ -879,8 +813,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     request.close();
 
     args.put("hl.fl", "foo_*");
-    lrf = h.getRequestFactory("", 0, 10, args);
-    request = lrf.makeRequest("test");
+    request = req(args, "q", "test");
     highlighter = getHighlighter();
     highlightFieldNames = Arrays.asList(highlighter.getHighlightFields(null,
         request, new String[] {}));
@@ -892,12 +825,11 @@ public class HighlighterTest extends SolrTestCaseJ4 {
 
     // SOLR-5127
     args.put("hl.fl", (random().nextBoolean() ? "foo_*,bar_*" : 
"bar_*,foo_*"));
-    lrf = h.getRequestFactory("", 0, 10, args);
     // hl.fl ordering need not be preserved in output
     final Set<String> highlightedSetExpected = new HashSet<String>();
     highlightedSetExpected.add("foo_s");
     highlightedSetExpected.add("bar_s");
-    try (LocalSolrQueryRequest localRequest = lrf.makeRequest("test")) {
+    try (var localRequest = req(args, "q", "test")) {
       highlighter = getHighlighter();
       final Set<String> highlightedSetActual = new HashSet<String>(
           Arrays.asList(highlighter.getHighlightFields(null,
@@ -907,8 +839,7 @@ public class HighlighterTest extends SolrTestCaseJ4 {
 
     // SOLR-11334
     args.put("hl.fl", "title, text"); // comma then space
-    lrf = h.getRequestFactory("", 0, 10, args);
-    request = lrf.makeRequest("test");
+    request = req(args, "q", "test");
     highlighter = getHighlighter();
     highlightFieldNames = Arrays.asList(highlighter.getHighlightFields(null,
         request, new String[] {}));
@@ -934,14 +865,12 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.fl", "");
     args.put("hl.usePhraseHighlighter", "true");
     args.put("hl.highlightMultiTerm", "true");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     assertU(adoc("t_text", "a long day's night", "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("lon*"),
+        req(args, "q", "lon*"),
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='t_text']/str"
             );
@@ -958,17 +887,15 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     args.put("hl.fl", "");
     args.put("hl.usePhraseHighlighter", "true");
     args.put("hl.highlightMultiTerm", "true");
-    TestHarness.LocalRequestFactory sumLRF = h.getRequestFactory(
-      "", 0, 200, args);
     
     assertU(adoc("t_text", "a long day's night", "id", "1"));
     assertU(commit());
     assertU(optimize());
     assertQ("Basic summarization",
-            sumLRF.makeRequest("l*g"),
+        req(args, "q", "l*g",
             "//lst[@name='highlighting']/lst[@name='1']",
             "//lst[@name='1']/arr[@name='t_text']/str"
-            );
+            ));
 
   }
   
@@ -1253,4 +1180,14 @@ public class HighlighterTest extends SolrTestCaseJ4 {
     var hl = (HighlightComponent) 
h.getCore().getSearchComponents().get(HighlightComponent.COMPONENT_NAME);
     return hl.getHighlighter(new MapSolrParams(Map.of("hl.method", 
"original")));
   }
+
+  public static SolrQueryRequest req(String... moreArgs) {
+    return req(Map.of(), moreArgs);
+  }
+
+  private static SolrQueryRequest req(Map<String, String> args, String... 
moreArgs) {
+    SolrParams params = new MapSolrParams(Map.of(HighlightParams.METHOD, 
"original"));
+    params = SolrParams.wrapDefaults(new MapSolrParams(args), params);
+    return SolrTestCaseJ4.req(params, moreArgs);
+  }
 }
diff --git a/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java 
b/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java
index d484b35..ed869b0 100644
--- a/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java
+++ b/solr/core/src/test/org/apache/solr/request/TestWriterPerf.java
@@ -175,7 +175,7 @@ public class TestWriterPerf extends SolrTestCaseJ4 {
                     ,"facet.limit","100"
                     ,"facet.sort","count"
                     ,"hl","true"
-                    ,"hl.fl","t1"
+                    ,"hl.fl", t1
             );
 
 
diff --git 
a/solr/core/src/test/org/apache/solr/search/TestSurroundQueryParser.java 
b/solr/core/src/test/org/apache/solr/search/TestSurroundQueryParser.java
index 8a6d7e2..bd1c513 100644
--- a/solr/core/src/test/org/apache/solr/search/TestSurroundQueryParser.java
+++ b/solr/core/src/test/org/apache/solr/search/TestSurroundQueryParser.java
@@ -93,8 +93,12 @@ public class TestSurroundQueryParser extends SolrTestCaseJ4 {
         ,"//lst[@name='1']/arr[@name='name']/str[.='a b c d e a b c f g h i j 
<em>k</em> <em>l</em> m l k j z z z']");
 
     // test highlighted response with ordered query and 
hl.usePhraseHighlighter=false
-    assertQ(req("q", "{!surround df=name}k w l", 
-                "hl", "true", 
+    //  Note: UnifiedHighlighter doesn't support it because RewriteQuery 
doesn't implement visit(),
+    //   but it will work with usePhraseHighlighter (and thus weight.matches 
mode)
+    //   which is the default (as seen above).  See SOLR-15962
+    assertQ(req("q", "{!surround df=name}k w l",
+                "hl", "true",
+                "hl.method", "original",
                 "hl.fl", "name", 
                 "hl.usePhraseHighlighter", "false")
         ,"//*[@numFound='1']"
diff --git 
a/solr/modules/clustering/src/java/org/apache/solr/handler/clustering/ClusteringComponent.java
 
b/solr/modules/clustering/src/java/org/apache/solr/handler/clustering/ClusteringComponent.java
index ca058f4..de044c5 100644
--- 
a/solr/modules/clustering/src/java/org/apache/solr/handler/clustering/ClusteringComponent.java
+++ 
b/solr/modules/clustering/src/java/org/apache/solr/handler/clustering/ClusteringComponent.java
@@ -372,28 +372,25 @@ public class ClusteringComponent extends SearchComponent 
implements SolrCoreAwar
     SolrQueryRequest req = null;
     SolrHighlighter highlighter = null;
     if (preferQueryContext) {
-      highlighter =
+      // TODO switch to hl.method=unified
+      highlighter = // never null
           ((HighlightComponent) 
core.getSearchComponents().get(HighlightComponent.COMPONENT_NAME))
-              .getHighlighter(new ModifiableSolrParams());
-      if (highlighter != null) {
-        Map<String, Object> args = new HashMap<>();
-        args.put(HighlightParams.FIELDS, fieldsToCluster);
-        args.put(HighlightParams.HIGHLIGHT, "true");
-        // We don't want any highlight marks.
-        args.put(HighlightParams.SIMPLE_PRE, "");
-        args.put(HighlightParams.SIMPLE_POST, "");
-        args.put(HighlightParams.FRAGSIZE, requestParameters.contextSize());
-        args.put(HighlightParams.SNIPPETS, requestParameters.contextCount());
-        req = new LocalSolrQueryRequest(core, query.toString(), "", 0, 1, 
args) {
-          @Override
-          public SolrIndexSearcher getSearcher() {
-            return indexSearcher;
-          }
-        };
-      } else {
-        log.warn("No highlighter configured, cannot produce summary");
-        preferQueryContext = false;
-      }
+              .getHighlighter(new 
ModifiableSolrParams().add(HighlightParams.METHOD, "original"));
+      Map<String, Object> args = new HashMap<>();
+      args.put(HighlightParams.FIELDS, fieldsToCluster);
+      args.put(HighlightParams.HIGHLIGHT, "true");
+      // We don't want any highlight marks.
+      args.put(HighlightParams.SIMPLE_PRE, "");
+      args.put(HighlightParams.SIMPLE_POST, "");
+      args.put(HighlightParams.FRAGSIZE, requestParameters.contextSize());
+      args.put(HighlightParams.SNIPPETS, requestParameters.contextCount());
+      // TODO highlight all docs at once instead of 1-by-1
+      req = new LocalSolrQueryRequest(core, query.toString(), "", 0, 1, args) {
+        @Override
+        public SolrIndexSearcher getSearcher() {
+          return indexSearcher;
+        }
+      };
     }
 
     Map<String, Function<IndexableField, String>> fieldsToLoad = new 
LinkedHashMap<>();
diff --git a/solr/server/solr/configsets/_default/conf/solrconfig.xml 
b/solr/server/solr/configsets/_default/conf/solrconfig.xml
index b6ec37e..c28ed6f 100644
--- a/solr/server/solr/configsets/_default/conf/solrconfig.xml
+++ b/solr/server/solr/configsets/_default/conf/solrconfig.xml
@@ -846,6 +846,8 @@
        https://solr.apache.org/guide/highlighting.html
     -->
   <searchComponent class="solr.HighlightComponent" name="highlight">
+    <!-- note: the hl.method=unified highlighter is not configured here; it's 
completely configured
+    via parameters.  The below configuration supports hl.method=original and 
fastVector. -->
     <highlighting>
       <!-- Configure the standard fragmenter -->
       <!-- This could most likely be commented out in the "default" case -->
diff --git 
a/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml 
b/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml
index 6f56dce..3e55f13 100644
--- 
a/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml
+++ 
b/solr/server/solr/configsets/sample_techproducts_configs/conf/solrconfig.xml
@@ -1110,6 +1110,8 @@
        https://solr.apache.org/guide/highlighting.html
     -->
   <searchComponent class="solr.HighlightComponent" name="highlight">
+    <!-- note: the hl.method=unified highlighter is not configured here; it's 
completely configured
+via parameters.  The below configuration supports hl.method=original and 
fastVector. -->
     <highlighting>
       <!-- Configure the standard fragmenter -->
       <!-- This could most likely be commented out in the "default" case -->
diff --git a/solr/solr-ref-guide/src/highlighting.adoc 
b/solr/solr-ref-guide/src/highlighting.adoc
index 87bf571..3306c3f 100644
--- a/solr/solr-ref-guide/src/highlighting.adoc
+++ b/solr/solr-ref-guide/src/highlighting.adoc
@@ -46,10 +46,10 @@ If you want to use highlighting, you must set this to 
`true`.
 +
 [%autowidth,frame=none]
 |===
-|Optional |Default: `orignal`
+|Optional |Default: `unified`
 |===
 +
-The highlighting implementation to use.
+The highlighting implementation/engine to use.
 Acceptable values are: `unified`, `original`, `fastVector`.
 +
 See the <<Choosing a Highlighter>> section below for more details on the 
differences between the available highlighters.
@@ -248,18 +248,18 @@ When there is a match to the query term in that field, it 
will be included for e
 == Choosing a Highlighter
 
 Solr provides a `HighlightComponent` (a 
<<requesthandlers-searchcomponents.adoc#defining-search-components,`SearchComponent`>>)
 and it's in the default list of components for search handlers.
-It offers a somewhat unified API over multiple actual highlighting 
implementations (or simply "highlighters") that do the business of highlighting.
+It offers a somewhat unified API over multiple actual highlighting 
implementations / engines (or simply "highlighters") that do the business of 
highlighting.
 
 There are many parameters supported by more than one highlighter, and 
sometimes the implementation details and semantics will be a bit different, so 
don't expect identical results when switching highlighters.
-You should use the `hl.method` parameter to choose a highlighter but it's also 
possible to explicitly configure an implementation by class name in 
`solrconfig.xml`.
+You should use the `hl.method` parameter to choose a highlighter.
 
-There are four highlighters available that can be chosen at runtime with the 
`hl.method` parameter, in order of general recommendation:
+There are three highlighters available that can be chosen at runtime with the 
`hl.method` parameter, in order of general recommendation:
 
 <<Unified Highlighter>>:: (`hl.method=unified`)
 +
 The Unified Highlighter is the newest highlighter (as of Solr 6.4), which 
stands out as the most performant and accurate of the options.
 It can handle typical requirements and others possibly via plugins/extension.
-We recommend that you try this highlighter even though it isn't the default 
(yet).
+We recommend that you use this highlighter as a first choice.
 +
 The UH highlights a query very _accurately_ and thus is true to what the 
underlying Lucene query actually matches.
 Other highlighters highlight terms more liberally (over-highlight).
@@ -274,7 +274,7 @@ Passage scoring does not consider boosts in the query.
 Some users want more/better passage breaking flexibility.
 The "alternate" fallback options are more primitive.
 
-<<Original Highlighter>>:: (`hl.method=original`, the default)
+<<Original Highlighter>>:: (`hl.method=original`)
 +
 The Original Highlighter, sometimes called the "Standard Highlighter" or 
"Default Highlighter", is Lucene's original highlighter – a venerable option 
with a high degree of customization options.
 Its query accuracy is good enough for most needs, although it's not quite as 
good/perfect as the Unified Highlighter.
@@ -299,7 +299,6 @@ This highlighter's query-representation is less advanced 
than the Original or Un
 Both the FastVector and Original Highlighters can be used in conjunction in a 
search request to highlight some fields with one and some the other.
 In contrast, the Unified Highlighter can only be chosen exclusively.
 
-
 The Unified Highlighter is exclusively configured via search parameters.
 In contrast, some settings for the Original and FastVector Highlighters are 
set in `solrconfig.xml`.
 There's a robust example of the latter in the "techproducts" configset.
@@ -491,7 +490,7 @@ This character will still appear in the text as the last 
character of a passage.
 +
 Tells the UH to use Lucene's "Weight Matches" API instead of doing `SpanQuery` 
conversion.
 This is the most accurate highlighting mode reflecting the query.
-Furthermore, phrases will be highlighted as a whole instead of word by word.
+Furthermore, phrases will be highlighted as a whole instead of word by word.  
Currently, this setting slows down the unified highlighter a lot when many 
fields are highlighted.
 +
 If either `hl.usePhraseHighlighter` or `hl.multiTermQuery` are set to `false`, 
then this setting is effectively `false` no matter what you set it to.
 
diff --git a/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc 
b/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
index bce04cf..fa4f4a3 100644
--- a/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
+++ b/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
@@ -164,6 +164,9 @@ values serialized in this way will need to be updated 
accordingly.
 
 * SOLR-9575: Solr no longer requires a `solr.xml` in `$SOLR_HOME`. If one is 
not found, Solr will instead use the default one from 
`$SOLR_TIP/server/solr/solr.xml`. You can revert to the pre-9.0 behaviour by 
setting environment variable `SOLR_SOLRXML_REQUIRED=true` or system property 
`-Dsolr.solrxml.required=true`. Solr also does not require a `zoo.cfg` in 
`$SOLR_HOME` if started with embedded zookeeper.
 
+* SOLR-12901: Highlighting: hl.method=unified is the new default.  Use 
hl.method=original
+  to switch back if needed.
+
 === solr.xml maxBooleanClauses now enforced recursively
 
 Lucene 9.0 has additional safety checks over previous versions that impact how 
the `solr.xml` global 
`<<configuring-solr-xml#global-maxbooleanclauses,maxBooleanClauses>>` option is 
enforced.

Reply via email to