You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by be...@apache.org on 2023/05/12 13:54:18 UTC

[lucene] branch branch_9x updated: [Backport] GITHUB-11838 Add api to allow concurrent query rewrite (#12197)

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

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


The following commit(s) were added to refs/heads/branch_9x by this push:
     new ba91ef97970 [Backport] GITHUB-11838 Add api to allow concurrent query rewrite (#12197)
ba91ef97970 is described below

commit ba91ef97970e5418f9388afabb4cfa131a1e86b3
Author: Benjamin Trent <be...@gmail.com>
AuthorDate: Fri May 12 09:54:12 2023 -0400

    [Backport] GITHUB-11838 Add api to allow concurrent query rewrite (#12197)
    
    * GITHUB-11838 Change API to allow concurrent query rewrite (#11840)
    
    Replace Query#rewrite(IndexReader) with Query#rewrite(IndexSearcher)
    
    Co-authored-by: Patrick Zhai <zh...@users.noreply.github.com>
    Co-authored-by: Adrien Grand <jp...@gmail.com>
    
    Backport of https://github.com/apache/lucene/pull/11840
    
    Changes from original:
     - Query keeps `rewrite(IndexReader)`, but it is now deprecated
     - VirtualMethod is used to correct delegate to the overridden methods
     - The changes to `RewriteMethod` type classes are reverted, this increased the backwards compatibility impact.
    
    ------------------------------
    
    ### Description
    Issue: #11838
    
    #### Updated Proposal
     * Change signature of rewrite to `rewrite(IndexSearcher)`
     * How did I migrate the usage:
       * Use Intellij to do preliminary refactoring for me
       * For test usage, use searcher whenever is available, otherwise create one using `newSearcher(reader)`
       * For very few non-test classes which doesn't have IndexSearcher available but called rewrite, create a searcher using `new IndexSearcher(reader)`, tried my best to avoid creating it recurrently (Especially in `FieldQuery`)
       * For queries who have implemented the rewrite and uses some part of reader's functionality, use shortcut method when possible, otherwise pull out the reader from indexSearcher.
---
 lucene/CHANGES.txt                                 |   4 +-
 .../classification/utils/NearestFuzzyQuery.java    |   4 +-
 .../document/BinaryRangeFieldRangeQuery.java       |   5 +-
 .../lucene/document/DoubleRangeSlowRangeQuery.java |   6 +-
 .../org/apache/lucene/document/FeatureField.java   |   9 +-
 .../org/apache/lucene/document/FeatureQuery.java   |   7 +-
 .../lucene/document/FloatRangeSlowRangeQuery.java  |   6 +-
 .../lucene/document/IntRangeSlowRangeQuery.java    |   6 +-
 .../lucene/document/LongRangeSlowRangeQuery.java   |   6 +-
 .../document/SortedNumericDocValuesRangeQuery.java |   5 +-
 .../document/SortedNumericDocValuesSetQuery.java   |   5 +-
 .../document/SortedSetDocValuesRangeQuery.java     |   5 +-
 .../lucene/search/AbstractKnnVectorQuery.java      |   4 +-
 .../org/apache/lucene/search/BlendedTermQuery.java |  10 +-
 .../org/apache/lucene/search/BooleanQuery.java     |   9 +-
 .../java/org/apache/lucene/search/BoostQuery.java  |   7 +-
 .../apache/lucene/search/ConstantScoreQuery.java   |   8 +-
 .../apache/lucene/search/DisjunctionMaxQuery.java  |   8 +-
 .../apache/lucene/search/DoubleValuesSource.java   |   3 +-
 .../org/apache/lucene/search/FieldExistsQuery.java |   5 +-
 .../lucene/search/IndexOrDocValuesQuery.java       |   7 +-
 .../org/apache/lucene/search/IndexSearcher.java    |   4 +-
 .../IndexSortSortedNumericDocValuesRangeQuery.java |   5 +-
 .../org/apache/lucene/search/MultiPhraseQuery.java |   5 +-
 .../org/apache/lucene/search/MultiTermQuery.java   |   8 +-
 .../org/apache/lucene/search/NGramPhraseQuery.java |   9 +-
 .../org/apache/lucene/search/NamedMatches.java     |   5 +-
 .../java/org/apache/lucene/search/PhraseQuery.java |   5 +-
 .../src/java/org/apache/lucene/search/Query.java   |  32 ++-
 .../org/apache/lucene/search/ScoringRewrite.java   |   3 +-
 .../org/apache/lucene/search/SynonymQuery.java     |   3 +-
 .../org/apache/lucene/search/TopTermsRewrite.java  |   3 +-
 .../org/apache/lucene/search/package-info.java     |  10 +-
 .../lucene/search/BaseKnnVectorQueryTestCase.java  |   8 +-
 .../apache/lucene/search/TestBooleanRewrites.java  |   4 +-
 .../apache/lucene/search/TestFieldExistsQuery.java |  18 +-
 ...tIndexSortSortedNumericDocValuesRangeQuery.java |   4 +-
 .../apache/lucene/search/TestMatchNoDocsQuery.java |   4 +-
 .../apache/lucene/search/TestMatchesIterator.java  |   2 +-
 .../apache/lucene/search/TestNGramPhraseQuery.java |  10 +-
 .../org/apache/lucene/search/TestNeedsScores.java  |   6 +-
 .../org/apache/lucene/search/TestPhraseQuery.java  |   2 +-
 .../TestQueryRewriteBackwardsCompatibility.java    | 269 +++++++++++++++++++++
 .../org/apache/lucene/search/TestWANDScorer.java   |   6 +-
 .../org/apache/lucene/facet/DrillDownQuery.java    |   8 +-
 .../apache/lucene/facet/DrillSidewaysQuery.java    |  11 +-
 .../org/apache/lucene/facet/range/DoubleRange.java |  13 +-
 .../org/apache/lucene/facet/range/LongRange.java   |  13 +-
 .../apache/lucene/facet/TestDrillDownQuery.java    |   3 +-
 .../org/apache/lucene/facet/TestDrillSideways.java |   2 +-
 .../lucene/facet/range/TestRangeFacetCounts.java   |   6 +-
 .../highlight/WeightedSpanTermExtractor.java       |   2 +-
 .../search/uhighlight/UnifiedHighlighter.java      |  10 +-
 .../lucene/search/vectorhighlight/FieldQuery.java  |  37 +--
 .../lucene/search/highlight/TestHighlighter.java   |   4 +-
 .../highlight/custom/TestHighlightCustomQuery.java |   4 +-
 .../search/uhighlight/TestUnifiedHighlighter.java  |   2 +-
 .../uhighlight/TestUnifiedHighlighterMTQ.java      |   4 +-
 .../TestUnifiedHighlighterStrictPhrases.java       |   4 +-
 .../search/vectorhighlight/AbstractTestCase.java   |   8 +-
 .../search/vectorhighlight/TestFieldQuery.java     |  12 +-
 .../search/join/ParentChildrenBlockJoinQuery.java  |   7 +-
 .../lucene/search/join/ToChildBlockJoinQuery.java  |   7 +-
 .../lucene/search/join/ToParentBlockJoinQuery.java |   7 +-
 .../lucene/luke/models/search/SearchImpl.java      |   2 +-
 .../search/TestDiversifiedTopDocsCollector.java    |   6 +-
 .../lucene/monitor/ForceNoBulkScoringQuery.java    |   7 +-
 .../org/apache/lucene/monitor/MonitorTestBase.java |   4 +-
 .../monitor/TestForceNoBulkScoringQuery.java       |   2 +-
 .../apache/lucene/queries/CommonTermsQuery.java    |   4 +-
 .../queries/function/FunctionScoreQuery.java       |   5 +-
 .../lucene/queries/mlt/MoreLikeThisQuery.java      |   6 +-
 .../lucene/queries/payloads/PayloadScoreQuery.java |   7 +-
 .../queries/payloads/SpanPayloadCheckQuery.java    |   7 +-
 .../queries/spans/FieldMaskingSpanQuery.java       |   7 +-
 .../lucene/queries/spans/SpanContainQuery.java     |   9 +-
 .../queries/spans/SpanMultiTermQueryWrapper.java   |   4 +-
 .../apache/lucene/queries/spans/SpanNearQuery.java |   7 +-
 .../apache/lucene/queries/spans/SpanNotQuery.java  |   9 +-
 .../apache/lucene/queries/spans/SpanOrQuery.java   |   7 +-
 .../queries/spans/SpanPositionCheckQuery.java      |   7 +-
 .../lucene/queries/function/TestValueSources.java  |   4 +-
 .../lucene/queries/spans/AssertingSpanQuery.java   |   7 +-
 .../queries/spans/TestFieldMaskingSpanQuery.java   |   2 +-
 .../complexPhrase/ComplexPhraseQueryParser.java    |   5 +-
 .../surround/query/DistanceRewriteQuery.java       |   6 +-
 .../queryparser/surround/query/RewriteQuery.java   |   4 +-
 .../surround/query/SimpleTermRewriteQuery.java     |   6 +-
 .../lucene/queryparser/xml/TestCoreParser.java     |   2 +-
 .../lucene/sandbox/queries/FuzzyLikeThisQuery.java |   4 +-
 .../lucene/sandbox/search/CombinedFieldQuery.java  |   2 +-
 .../lucene/sandbox/search/CoveringQuery.java       |   9 +-
 .../lucene/sandbox/search/MultiRangeQuery.java     |   3 +-
 .../lucene/sandbox/search/PhraseWildcardQuery.java |   4 +-
 .../lucene/sandbox/search/TermAutomatonQuery.java  |   3 +-
 .../sandbox/queries/TestFuzzyLikeThisQuery.java    |   8 +-
 .../lucene/sandbox/search/TestCoveringQuery.java   |   3 +-
 .../sandbox/search/TestMultiRangeQueries.java      |   4 +-
 .../sandbox/search/TestTermAutomatonQuery.java     |  18 +-
 .../spatial/composite/CompositeVerifyQuery.java    |   7 +-
 .../lucene/spatial/vector/PointVectorStrategy.java |   5 +-
 .../search/suggest/document/CompletionQuery.java   |   8 +-
 .../suggest/document/SuggestIndexSearcher.java     |   2 +-
 .../apache/lucene/tests/search/AssertingQuery.java |   7 +-
 .../tests/search/BlockScoreQueryWrapper.java       |   7 +-
 .../tests/search/RandomApproximationQuery.java     |   7 +-
 106 files changed, 620 insertions(+), 335 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index e6019e40148..2f3a572a1bf 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -7,7 +7,9 @@ http://s.apache.org/luceneversions
 
 API Changes
 ---------------------
-(No changes)
+
+* GITHUB#11840: Query rewrite now takes an IndexSearcher instead of IndexReader to enable concurrent
+  rewriting. (Patrick Zhai, Ben Trent)
 
 New Features
 ---------------------
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java b/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java
index c020d7487cb..12d11e59b9d 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java
@@ -35,6 +35,7 @@ import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.BoostQuery;
 import org.apache.lucene.search.FuzzyTermsEnum;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 import org.apache.lucene.search.TermQuery;
@@ -214,7 +215,8 @@ public class NearestFuzzyQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    IndexReader reader = indexSearcher.getIndexReader();
     ScoreTermQueue q = new ScoreTermQueue(MAX_NUM_TERMS);
     // load up the list of possible terms
     for (FieldVals f : fieldVals) {
diff --git a/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java
index ec814a4b0a7..b225f4d98fe 100644
--- a/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java
@@ -21,7 +21,6 @@ import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
 import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.ConstantScoreScorer;
@@ -90,8 +89,8 @@ abstract class BinaryRangeFieldRangeQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    return super.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return super.rewrite(indexSearcher);
   }
 
   private BinaryRangeDocValues getValues(LeafReader reader, String field) throws IOException {
diff --git a/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java
index 6406b1be81a..f0f9040d08c 100644
--- a/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java
@@ -20,7 +20,7 @@ package org.apache.lucene.document;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 
@@ -79,8 +79,8 @@ class DoubleRangeSlowRangeQuery extends BinaryRangeFieldRangeQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    return super.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return super.rewrite(indexSearcher);
   }
 
   private static byte[] encodeRanges(double[] min, double[] max) {
diff --git a/lucene/core/src/java/org/apache/lucene/document/FeatureField.java b/lucene/core/src/java/org/apache/lucene/document/FeatureField.java
index 27e68964459..85c3bad3519 100644
--- a/lucene/core/src/java/org/apache/lucene/document/FeatureField.java
+++ b/lucene/core/src/java/org/apache/lucene/document/FeatureField.java
@@ -31,6 +31,7 @@ import org.apache.lucene.search.BoostQuery;
 import org.apache.lucene.search.DoubleValuesSource;
 import org.apache.lucene.search.Explanation;
 import org.apache.lucene.search.FieldDoc;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.search.similarities.BM25Similarity;
@@ -223,7 +224,7 @@ public final class FeatureField extends Field {
 
     abstract Explanation explain(String field, String feature, float w, int freq);
 
-    FeatureFunction rewrite(IndexReader reader) throws IOException {
+    FeatureFunction rewrite(IndexSearcher indexSearcher) throws IOException {
       return this;
     }
   }
@@ -340,11 +341,11 @@ public final class FeatureField extends Field {
     }
 
     @Override
-    public FeatureFunction rewrite(IndexReader reader) throws IOException {
+    public FeatureFunction rewrite(IndexSearcher indexSearcher) throws IOException {
       if (pivot != null) {
-        return super.rewrite(reader);
+        return super.rewrite(indexSearcher);
       }
-      float newPivot = computePivotFeatureValue(reader, field, feature);
+      float newPivot = computePivotFeatureValue(indexSearcher.getIndexReader(), field, feature);
       return new SaturationFunction(field, feature, newPivot);
     }
 
diff --git a/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java b/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java
index de899a96d4e..8b1ea8c4725 100644
--- a/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.util.Objects;
 import org.apache.lucene.document.FeatureField.FeatureFunction;
 import org.apache.lucene.index.ImpactsEnum;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.Term;
@@ -52,12 +51,12 @@ final class FeatureQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    FeatureFunction rewritten = function.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    FeatureFunction rewritten = function.rewrite(indexSearcher);
     if (function != rewritten) {
       return new FeatureQuery(fieldName, featureName, rewritten);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java
index 9c011621e06..62981f4870a 100644
--- a/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java
@@ -20,7 +20,7 @@ package org.apache.lucene.document;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 
@@ -79,8 +79,8 @@ class FloatRangeSlowRangeQuery extends BinaryRangeFieldRangeQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    return super.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return super.rewrite(indexSearcher);
   }
 
   private static byte[] encodeRanges(float[] min, float[] max) {
diff --git a/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java
index cd0714a5290..99d5fa212f6 100644
--- a/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java
@@ -19,7 +19,7 @@ package org.apache.lucene.document;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 
@@ -77,8 +77,8 @@ class IntRangeSlowRangeQuery extends BinaryRangeFieldRangeQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    return super.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return super.rewrite(indexSearcher);
   }
 
   private static byte[] encodeRanges(int[] min, int[] max) {
diff --git a/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java
index a4c164524fc..b86d64bef62 100644
--- a/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java
@@ -20,7 +20,7 @@ package org.apache.lucene.document;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 
@@ -79,8 +79,8 @@ class LongRangeSlowRangeQuery extends BinaryRangeFieldRangeQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    return super.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return super.rewrite(indexSearcher);
   }
 
   private static byte[] encodeRanges(long[] min, long[] max) {
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
index fb23056126b..21264409136 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.document;
 import java.io.IOException;
 import java.util.Objects;
 import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.NumericDocValues;
 import org.apache.lucene.index.SortedNumericDocValues;
@@ -84,11 +83,11 @@ final class SortedNumericDocValuesRangeQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (lowerValue == Long.MIN_VALUE && upperValue == Long.MAX_VALUE) {
       return new FieldExistsQuery(field);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java
index 72d5d42b30a..fe5e8c3afed 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
 import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.NumericDocValues;
 import org.apache.lucene.index.SortedNumericDocValues;
@@ -85,11 +84,11 @@ final class SortedNumericDocValuesSetQuery extends Query implements Accountable
   }
 
   @Override
-  public Query rewrite(IndexReader indexReader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (numbers.size() == 0) {
       return new MatchNoDocsQuery();
     }
-    return super.rewrite(indexReader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
index f7eab990d3d..928257cbd1f 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.document;
 import java.io.IOException;
 import java.util.Objects;
 import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.SortedDocValues;
 import org.apache.lucene.index.SortedSetDocValues;
@@ -98,11 +97,11 @@ final class SortedSetDocValuesRangeQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (lowerValue == null && upperValue == null) {
       return new FieldExistsQuery(field);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java b/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java
index eaa7cc1e833..9403a6413e2 100644
--- a/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java
@@ -60,12 +60,12 @@ abstract class AbstractKnnVectorQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    IndexReader reader = indexSearcher.getIndexReader();
     TopDocs[] perLeafResults = new TopDocs[reader.leaves().size()];
 
     Weight filterWeight = null;
     if (filter != null) {
-      IndexSearcher indexSearcher = new IndexSearcher(reader);
       BooleanQuery booleanQuery =
           new BooleanQuery.Builder()
               .add(filter, BooleanClause.Occur.FILTER)
diff --git a/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java
index 8b73eb5b27a..2c7e41ac971 100644
--- a/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.search;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReaderContext;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
@@ -268,11 +267,12 @@ public final class BlendedTermQuery extends Query {
   }
 
   @Override
-  public final Query rewrite(IndexReader reader) throws IOException {
+  public final Query rewrite(IndexSearcher indexSearcher) throws IOException {
     final TermStates[] contexts = ArrayUtil.copyOfSubArray(this.contexts, 0, this.contexts.length);
     for (int i = 0; i < contexts.length; ++i) {
-      if (contexts[i] == null || contexts[i].wasBuiltFor(reader.getContext()) == false) {
-        contexts[i] = TermStates.build(reader.getContext(), terms[i], true);
+      if (contexts[i] == null
+          || contexts[i].wasBuiltFor(indexSearcher.getTopReaderContext()) == false) {
+        contexts[i] = TermStates.build(indexSearcher.getTopReaderContext(), terms[i], true);
       }
     }
 
@@ -287,7 +287,7 @@ public final class BlendedTermQuery extends Query {
     }
 
     for (int i = 0; i < contexts.length; ++i) {
-      contexts[i] = adjustFrequencies(reader.getContext(), contexts[i], df, ttf);
+      contexts[i] = adjustFrequencies(indexSearcher.getTopReaderContext(), contexts[i], df, ttf);
     }
 
     Query[] termQueries = new Query[terms.length];
diff --git a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java
index f5c69621b15..07823ae5c4d 100644
--- a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java
@@ -30,7 +30,6 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.Predicate;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.BooleanClause.Occur;
 
 /**
@@ -247,7 +246,7 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (clauses.size() == 0) {
       return new MatchNoDocsQuery("empty BooleanQuery");
     }
@@ -286,12 +285,12 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
         Query rewritten;
         if (occur == Occur.FILTER || occur == Occur.MUST_NOT) {
           // Clauses that are not involved in scoring can get some extra simplifications
-          rewritten = new ConstantScoreQuery(query).rewrite(reader);
+          rewritten = new ConstantScoreQuery(query).rewrite(indexSearcher);
           if (rewritten instanceof ConstantScoreQuery) {
             rewritten = ((ConstantScoreQuery) rewritten).getQuery();
           }
         } else {
-          rewritten = query.rewrite(reader);
+          rewritten = query.rewrite(indexSearcher);
         }
         if (rewritten != query || query.getClass() == MatchNoDocsQuery.class) {
           // rewrite clause
@@ -566,7 +565,7 @@ public class BooleanQuery extends Query implements Iterable<BooleanClause> {
       }
     }
 
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java
index 47c0f5f6f28..37526963700 100644
--- a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java
@@ -18,7 +18,6 @@ package org.apache.lucene.search;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 
 /**
  * A {@link Query} wrapper that allows to give a boost to the wrapped query. Boost values that are
@@ -73,8 +72,8 @@ public final class BoostQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query rewritten = query.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query rewritten = query.rewrite(indexSearcher);
 
     if (boost == 1f) {
       return rewritten;
@@ -99,7 +98,7 @@ public final class BoostQuery extends Query {
       return new BoostQuery(rewritten, boost);
     }
 
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java
index 2225cc10944..48f763e1646 100644
--- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java
@@ -18,7 +18,6 @@ package org.apache.lucene.search;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.util.Bits;
 
@@ -40,8 +39,9 @@ public final class ConstantScoreQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query rewritten = query.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+
+    Query rewritten = query.rewrite(indexSearcher);
 
     // Do some extra simplifications that are legal since scores are not needed on the wrapped
     // query.
@@ -70,7 +70,7 @@ public final class ConstantScoreQuery extends Query {
       return new ConstantScoreQuery(((BoostQuery) rewritten).getQuery());
     }
 
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java
index 8c41c0a37cf..1ab4f3b5081 100644
--- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java
@@ -23,7 +23,6 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 
 /**
@@ -209,11 +208,10 @@ public final class DisjunctionMaxQuery extends Query implements Iterable<Query>
   /**
    * Optimize our representation and our subqueries representations
    *
-   * @param reader the IndexReader we query
    * @return an optimized copy of us (which may not be a copy if there is nothing to optimize)
    */
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (disjuncts.isEmpty()) {
       return new MatchNoDocsQuery("empty DisjunctionMaxQuery");
     }
@@ -233,7 +231,7 @@ public final class DisjunctionMaxQuery extends Query implements Iterable<Query>
     boolean actuallyRewritten = false;
     List<Query> rewrittenDisjuncts = new ArrayList<>();
     for (Query sub : disjuncts) {
-      Query rewrittenSub = sub.rewrite(reader);
+      Query rewrittenSub = sub.rewrite(indexSearcher);
       actuallyRewritten |= rewrittenSub != sub;
       rewrittenDisjuncts.add(rewrittenSub);
     }
@@ -242,7 +240,7 @@ public final class DisjunctionMaxQuery extends Query implements Iterable<Query>
       return new DisjunctionMaxQuery(rewrittenDisjuncts, tieBreakerMultiplier);
     }
 
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java b/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java
index 303dc516af8..f27b791dd95 100644
--- a/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java
+++ b/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java
@@ -22,7 +22,6 @@ import java.util.Objects;
 import java.util.function.DoubleToLongFunction;
 import java.util.function.LongToDoubleFunction;
 import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.NumericDocValues;
 import org.apache.lucene.search.comparators.DoubleComparator;
@@ -85,7 +84,7 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
    *
    * <p>Queries that use DoubleValuesSource objects should call rewrite() during {@link
    * Query#createWeight(IndexSearcher, ScoreMode, float)} rather than during {@link
-   * Query#rewrite(IndexReader)} to avoid IndexReader reference leakage.
+   * Query#rewrite(IndexSearcher)} to avoid IndexReader reference leakage.
    *
    * <p>For the same reason, implementations that cache references to the IndexSearcher should
    * return a new object from this method.
diff --git a/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java b/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java
index 98c65b9ddd6..3d78df8e07c 100644
--- a/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java
@@ -108,7 +108,8 @@ public class FieldExistsQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    IndexReader reader = indexSearcher.getIndexReader();
     boolean allReadersRewritable = true;
 
     for (LeafReaderContext context : reader.leaves()) {
@@ -172,7 +173,7 @@ public class FieldExistsQuery extends Query {
     if (allReadersRewritable) {
       return new MatchAllDocsQuery();
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
index 9ba52eb674f..599608f0d84 100644
--- a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.search;
 import java.io.IOException;
 import org.apache.lucene.document.LongPoint;
 import org.apache.lucene.document.SortedNumericDocValuesField;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 
 /**
@@ -101,9 +100,9 @@ public final class IndexOrDocValuesQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query indexRewrite = indexQuery.rewrite(reader);
-    Query dvRewrite = dvQuery.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    Query indexRewrite = indexQuery.rewrite(indexSearcher);
+    Query dvRewrite = dvQuery.rewrite(indexSearcher);
     if (indexRewrite.getClass() == MatchAllDocsQuery.class
         || dvRewrite.getClass() == MatchAllDocsQuery.class) {
       return new MatchAllDocsQuery();
diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java
index 5798ea5d2cf..ce93bd9cef8 100644
--- a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java
+++ b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java
@@ -796,9 +796,9 @@ public class IndexSearcher {
    */
   public Query rewrite(Query original) throws IOException {
     Query query = original;
-    for (Query rewrittenQuery = query.rewrite(reader);
+    for (Query rewrittenQuery = query.rewrite(this);
         rewrittenQuery != query;
-        rewrittenQuery = query.rewrite(reader)) {
+        rewrittenQuery = query.rewrite(this)) {
       query = rewrittenQuery;
     }
     query.visit(getNumClausesCheckVisitor());
diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java
index eb2cf562994..b678d34192c 100644
--- a/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java
@@ -23,7 +23,6 @@ import java.util.Objects;
 import org.apache.lucene.document.IntPoint;
 import org.apache.lucene.document.LongPoint;
 import org.apache.lucene.index.DocValues;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.NumericDocValues;
@@ -133,12 +132,12 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (lowerValue == Long.MIN_VALUE && upperValue == Long.MAX_VALUE) {
       return new FieldExistsQuery(field);
     }
 
-    Query rewrittenFallback = fallbackQuery.rewrite(reader);
+    Query rewrittenFallback = fallbackQuery.rewrite(indexSearcher);
     if (rewrittenFallback.getClass() == MatchAllDocsQuery.class) {
       return new MatchAllDocsQuery();
     }
diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java
index 1bf34569c39..27819235f64 100644
--- a/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java
@@ -24,7 +24,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReaderContext;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
@@ -185,7 +184,7 @@ public class MultiPhraseQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (termArrays.length == 0) {
       return new MatchNoDocsQuery("empty MultiPhraseQuery");
     } else if (termArrays.length == 1) { // optimize one-term case
@@ -196,7 +195,7 @@ public class MultiPhraseQuery extends Query {
       }
       return builder.build();
     } else {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
   }
 
diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java
index 0dc6671dccc..44bd4279aba 100644
--- a/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java
@@ -18,9 +18,9 @@ package org.apache.lucene.search;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.FilteredTermsEnum; // javadocs
+import org.apache.lucene.index.FilteredTermsEnum;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.SingleTermsEnum; // javadocs
+import org.apache.lucene.index.SingleTermsEnum;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermStates;
 import org.apache.lucene.index.Terms;
@@ -321,8 +321,8 @@ public abstract class MultiTermQuery extends Query {
    * AttributeSource)}. For example, to rewrite to a single term, return a {@link SingleTermsEnum}
    */
   @Override
-  public final Query rewrite(IndexReader reader) throws IOException {
-    return rewriteMethod.rewrite(reader, this);
+  public final Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return rewriteMethod.rewrite(indexSearcher.getIndexReader(), this);
   }
 
   public RewriteMethod getRewriteMethod() {
diff --git a/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java
index 41b0decba7c..e5023bf032d 100644
--- a/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java
@@ -18,14 +18,13 @@ package org.apache.lucene.search;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
 
 /**
  * This is a {@link PhraseQuery} which is optimized for n-gram phrase query. For example, when you
  * query "ABCD" on a 2-gram field, you may want to use NGramPhraseQuery rather than {@link
- * PhraseQuery}, because NGramPhraseQuery will {@link #rewrite(IndexReader)} the query to "AB/0
- * CD/2", while {@link PhraseQuery} will query "AB/0 BC/1 CD/2" (where term/position).
+ * PhraseQuery}, because NGramPhraseQuery will {@link Query#rewrite(IndexSearcher)} the query to
+ * "AB/0 CD/2", while {@link PhraseQuery} will query "AB/0 BC/1 CD/2" (where term/position).
  */
 public class NGramPhraseQuery extends Query {
 
@@ -44,7 +43,7 @@ public class NGramPhraseQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     final Term[] terms = phraseQuery.getTerms();
     final int[] positions = phraseQuery.getPositions();
 
@@ -63,7 +62,7 @@ public class NGramPhraseQuery extends Query {
     }
 
     if (isOptimizable == false) {
-      return phraseQuery.rewrite(reader);
+      return phraseQuery.rewrite(indexSearcher);
     }
 
     PhraseQuery.Builder builder = new PhraseQuery.Builder();
diff --git a/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java b/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java
index 9a24f9433ba..d0ec5c3a212 100644
--- a/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java
+++ b/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java
@@ -25,7 +25,6 @@ import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 
 /**
@@ -113,8 +112,8 @@ public class NamedMatches implements Matches {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      Query rewritten = in.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      Query rewritten = in.rewrite(indexSearcher);
       if (rewritten != in) {
         return new NamedQuery(name, rewritten);
       }
diff --git a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java
index 93a2ace6453..64386165136 100644
--- a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java
@@ -24,7 +24,6 @@ import java.util.Objects;
 import org.apache.lucene.codecs.lucene90.Lucene90PostingsFormat;
 import org.apache.lucene.codecs.lucene90.Lucene90PostingsReader;
 import org.apache.lucene.index.ImpactsEnum;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReaderContext;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
@@ -284,7 +283,7 @@ public class PhraseQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (terms.length == 0) {
       return new MatchNoDocsQuery("empty PhraseQuery");
     } else if (terms.length == 1) {
@@ -296,7 +295,7 @@ public class PhraseQuery extends Query {
       }
       return new PhraseQuery(slop, terms, newPositions);
     } else {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
   }
 
diff --git a/lucene/core/src/java/org/apache/lucene/search/Query.java b/lucene/core/src/java/org/apache/lucene/search/Query.java
index 4f04728395d..3f36b8729cc 100644
--- a/lucene/core/src/java/org/apache/lucene/search/Query.java
+++ b/lucene/core/src/java/org/apache/lucene/search/Query.java
@@ -18,6 +18,7 @@ package org.apache.lucene.search;
 
 import java.io.IOException;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.util.VirtualMethod;
 
 /**
  * The abstract base class for queries.
@@ -45,6 +46,13 @@ import org.apache.lucene.index.IndexReader;
  */
 public abstract class Query {
 
+  private static final VirtualMethod<Query> oldMethod =
+      new VirtualMethod<>(Query.class, "rewrite", IndexReader.class);
+  private static final VirtualMethod<Query> newMethod =
+      new VirtualMethod<>(Query.class, "rewrite", IndexSearcher.class);
+  private final boolean isDeprecatedRewriteMethodOverridden =
+      VirtualMethod.compareImplementationDistance(this.getClass(), oldMethod, newMethod) > 0;
+
   /**
    * Prints a query to a string, with <code>field</code> assumed to be the default field and
    * omitted.
@@ -77,10 +85,32 @@ public abstract class Query {
    * <p>Callers are expected to call <code>rewrite</code> multiple times if necessary, until the
    * rewritten query is the same as the original query.
    *
+   * @deprecated Use {@link Query#rewrite(IndexSearcher)}
    * @see IndexSearcher#rewrite(Query)
    */
+  @Deprecated
   public Query rewrite(IndexReader reader) throws IOException {
-    return this;
+    return isDeprecatedRewriteMethodOverridden ? this : rewrite(new IndexSearcher(reader));
+  }
+
+  /**
+   * Expert: called to re-write queries into primitive queries. For example, a PrefixQuery will be
+   * rewritten into a BooleanQuery that consists of TermQuerys.
+   *
+   * <p>Callers are expected to call <code>rewrite</code> multiple times if necessary, until the
+   * rewritten query is the same as the original query.
+   *
+   * <p>The rewrite process may be able to make use of IndexSearcher's executor and be executed in
+   * parallel if the executor is provided.
+   *
+   * <p>However, if any of the intermediary queries do not satisfy the new API, parallel rewrite is
+   * not possible for any subsequent sub-queries. To take advantage of this API, the entire query
+   * tree must override this method.
+   *
+   * @see IndexSearcher#rewrite(Query)
+   */
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return isDeprecatedRewriteMethodOverridden ? rewrite(indexSearcher.getIndexReader()) : this;
   }
 
   /**
diff --git a/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java b/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java
index debc3efae15..5873b83075b 100644
--- a/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java
+++ b/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java
@@ -101,8 +101,7 @@ public abstract class ScoringRewrite<B> extends TermCollectingRewrite<B> {
   protected abstract void checkMaxClauseCount(int count) throws IOException;
 
   @Override
-  public final Query rewrite(final IndexReader reader, final MultiTermQuery query)
-      throws IOException {
+  public final Query rewrite(IndexReader reader, final MultiTermQuery query) throws IOException {
     final B builder = getTopLevelBuilder();
     final ParallelArraysTermCollector col = new ParallelArraysTermCollector();
     collectTerms(reader, query, col);
diff --git a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java
index 09ada782068..7e314870f9c 100644
--- a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java
@@ -29,7 +29,6 @@ import org.apache.lucene.index.Impact;
 import org.apache.lucene.index.Impacts;
 import org.apache.lucene.index.ImpactsEnum;
 import org.apache.lucene.index.ImpactsSource;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.SlowImpactsEnum;
@@ -153,7 +152,7 @@ public final class SynonymQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     // optimize zero and non-boosted single term cases
     if (terms.length == 0) {
       return new BooleanQuery.Builder().build();
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java b/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java
index 067867ca734..b5c52ba7ced 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java
@@ -61,8 +61,7 @@ public abstract class TopTermsRewrite<B> extends TermCollectingRewrite<B> {
   protected abstract int getMaxSize();
 
   @Override
-  public final Query rewrite(final IndexReader reader, final MultiTermQuery query)
-      throws IOException {
+  public final Query rewrite(IndexReader reader, final MultiTermQuery query) throws IOException {
     final int maxSize = Math.min(size, getMaxSize());
     final PriorityQueue<ScoreTerm> stQueue = new PriorityQueue<>();
     collectTerms(
diff --git a/lucene/core/src/java/org/apache/lucene/search/package-info.java b/lucene/core/src/java/org/apache/lucene/search/package-info.java
index 4f606597d0a..31a9d4018c8 100644
--- a/lucene/core/src/java/org/apache/lucene/search/package-info.java
+++ b/lucene/core/src/java/org/apache/lucene/search/package-info.java
@@ -357,11 +357,11 @@
  *       each Query implementation must provide an implementation of Weight. See the subsection on
  *       <a href="#weightClass">The Weight Interface</a> below for details on implementing the
  *       Weight interface.
- *   <li>{@link org.apache.lucene.search.Query#rewrite(org.apache.lucene.index.IndexReader)
- *       rewrite(IndexReader reader)} &mdash; Rewrites queries into primitive queries. Primitive
- *       queries are: {@link org.apache.lucene.search.TermQuery TermQuery}, {@link
- *       org.apache.lucene.search.BooleanQuery BooleanQuery}, <span >and other queries that
- *       implement {@link org.apache.lucene.search.Query#createWeight(IndexSearcher,ScoreMode,float)
+ *   <li>{@link org.apache.lucene.search.Query#rewrite(IndexSearcher) rewrite(IndexSearcher
+ *       searcher)} &mdash; Rewrites queries into primitive queries. Primitive queries are: {@link
+ *       org.apache.lucene.search.TermQuery TermQuery}, {@link org.apache.lucene.search.BooleanQuery
+ *       BooleanQuery}, <span >and other queries that implement {@link
+ *       org.apache.lucene.search.Query#createWeight(IndexSearcher,ScoreMode,float)
  *       createWeight(IndexSearcher searcher,ScoreMode scoreMode, float boost)}</span>
  * </ol>
  *
diff --git a/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java b/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java
index ce1fa6d7abb..af91b19444b 100644
--- a/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java
+++ b/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java
@@ -236,7 +236,7 @@ abstract class BaseKnnVectorQueryTestCase extends LuceneTestCase {
             getIndexStore("field", new float[] {0, 1}, new float[] {1, 2}, new float[] {0, 0});
         IndexReader reader = DirectoryReader.open(indexStore)) {
       AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3);
-      Query dasq = query.rewrite(reader);
+      Query dasq = query.rewrite(newSearcher(reader));
       IndexSearcher leafSearcher = newSearcher(reader.leaves().get(0).reader());
       expectThrows(
           IllegalStateException.class,
@@ -256,7 +256,7 @@ abstract class BaseKnnVectorQueryTestCase extends LuceneTestCase {
       try (IndexReader reader = DirectoryReader.open(d)) {
         IndexSearcher searcher = new IndexSearcher(reader);
         AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3);
-        Query dasq = query.rewrite(reader);
+        Query dasq = query.rewrite(searcher);
         Scorer scorer =
             dasq.createWeight(searcher, ScoreMode.COMPLETE, 1).scorer(reader.leaves().get(0));
         // before advancing the iterator
@@ -283,7 +283,7 @@ abstract class BaseKnnVectorQueryTestCase extends LuceneTestCase {
         IndexReader reader = DirectoryReader.open(d)) {
       IndexSearcher searcher = new IndexSearcher(reader);
       AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3);
-      Query rewritten = query.rewrite(reader);
+      Query rewritten = query.rewrite(searcher);
       Weight weight = searcher.createWeight(rewritten, ScoreMode.COMPLETE, 1);
       Scorer scorer = weight.scorer(reader.leaves().get(0));
 
@@ -322,7 +322,7 @@ abstract class BaseKnnVectorQueryTestCase extends LuceneTestCase {
         assertEquals(1, reader.leaves().size());
         IndexSearcher searcher = new IndexSearcher(reader);
         AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3);
-        Query rewritten = query.rewrite(reader);
+        Query rewritten = query.rewrite(searcher);
         Weight weight = searcher.createWeight(rewritten, ScoreMode.COMPLETE, 1);
         Scorer scorer = weight.scorer(reader.leaves().get(0));
 
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java
index 74badd25e77..87b8068d2f1 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java
@@ -83,7 +83,7 @@ public class TestBooleanRewrites extends LuceneTestCase {
     query1.add(new TermQuery(new Term("field", "a")), Occur.FILTER);
 
     // Single clauses rewrite to a term query
-    final Query rewritten1 = query1.build().rewrite(reader);
+    final Query rewritten1 = query1.build().rewrite(searcher);
     assertTrue(rewritten1 instanceof BoostQuery);
     assertEquals(0f, ((BoostQuery) rewritten1).getBoost(), 0f);
 
@@ -946,7 +946,7 @@ public class TestBooleanRewrites extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader indexReader) {
+    public Query rewrite(IndexSearcher indexSearcher) {
       numRewrites++;
       return this;
     }
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java
index 307d6800aa5..209ad510889 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java
@@ -63,7 +63,8 @@ public class TestFieldExistsQuery extends LuceneTestCase {
     final IndexReader reader = iw.getReader();
     iw.close();
 
-    assertTrue((new FieldExistsQuery("f")).rewrite(reader) instanceof MatchAllDocsQuery);
+    assertTrue(
+        (new FieldExistsQuery("f")).rewrite(newSearcher(reader)) instanceof MatchAllDocsQuery);
     reader.close();
     dir.close();
   }
@@ -82,7 +83,8 @@ public class TestFieldExistsQuery extends LuceneTestCase {
     final IndexReader reader = iw.getReader();
     iw.close();
 
-    assertTrue(new FieldExistsQuery("dim").rewrite(reader) instanceof MatchAllDocsQuery);
+    assertTrue(
+        new FieldExistsQuery("dim").rewrite(newSearcher(reader)) instanceof MatchAllDocsQuery);
     reader.close();
     dir.close();
   }
@@ -106,9 +108,10 @@ public class TestFieldExistsQuery extends LuceneTestCase {
     iw.commit();
     final IndexReader reader = iw.getReader();
     iw.close();
+    final IndexSearcher searcher = newSearcher(reader);
 
-    assertFalse((new FieldExistsQuery("dim")).rewrite(reader) instanceof MatchAllDocsQuery);
-    assertFalse((new FieldExistsQuery("f")).rewrite(reader) instanceof MatchAllDocsQuery);
+    assertFalse((new FieldExistsQuery("dim")).rewrite(searcher) instanceof MatchAllDocsQuery);
+    assertFalse((new FieldExistsQuery("f")).rewrite(searcher) instanceof MatchAllDocsQuery);
     reader.close();
     dir.close();
   }
@@ -127,10 +130,11 @@ public class TestFieldExistsQuery extends LuceneTestCase {
     iw.commit();
     final IndexReader reader = iw.getReader();
     iw.close();
+    final IndexSearcher searcher = newSearcher(reader);
 
-    assertFalse((new FieldExistsQuery("dv1")).rewrite(reader) instanceof MatchAllDocsQuery);
-    assertFalse((new FieldExistsQuery("dv2")).rewrite(reader) instanceof MatchAllDocsQuery);
-    assertFalse((new FieldExistsQuery("dv3")).rewrite(reader) instanceof MatchAllDocsQuery);
+    assertFalse((new FieldExistsQuery("dv1")).rewrite(searcher) instanceof MatchAllDocsQuery);
+    assertFalse((new FieldExistsQuery("dv2")).rewrite(searcher) instanceof MatchAllDocsQuery);
+    assertFalse((new FieldExistsQuery("dv3")).rewrite(searcher) instanceof MatchAllDocsQuery);
     reader.close();
     dir.close();
   }
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java
index 8df8dcb1917..cc5d8800e8a 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java
@@ -339,7 +339,7 @@ public class TestIndexSortSortedNumericDocValuesRangeQuery extends LuceneTestCas
     IndexReader reader = writer.getReader();
 
     Query query = createQuery("field", Long.MIN_VALUE, Long.MAX_VALUE);
-    Query rewrittenQuery = query.rewrite(reader);
+    Query rewrittenQuery = query.rewrite(newSearcher(reader));
     assertEquals(new FieldExistsQuery("field"), rewrittenQuery);
 
     writer.close();
@@ -357,7 +357,7 @@ public class TestIndexSortSortedNumericDocValuesRangeQuery extends LuceneTestCas
     Query fallbackQuery = new BooleanQuery.Builder().build();
     Query query = new IndexSortSortedNumericDocValuesRangeQuery("field", 1, 42, fallbackQuery);
 
-    Query rewrittenQuery = query.rewrite(reader);
+    Query rewrittenQuery = query.rewrite(newSearcher(reader));
     assertNotEquals(query, rewrittenQuery);
     assertThat(rewrittenQuery, instanceOf(IndexSortSortedNumericDocValuesRangeQuery.class));
 
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java
index e1facc81e61..43db42cc1d3 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java
@@ -44,7 +44,7 @@ public class TestMatchNoDocsQuery extends LuceneTestCase {
     assertEquals(query.toString(), "MatchNoDocsQuery(\"\")");
     query = new MatchNoDocsQuery("field 'title' not found");
     assertEquals(query.toString(), "MatchNoDocsQuery(\"field 'title' not found\")");
-    Query rewrite = query.rewrite(null);
+    Query rewrite = query.rewrite((IndexSearcher) null);
     assertTrue(rewrite instanceof MatchNoDocsQuery);
     assertEquals(rewrite.toString(), "MatchNoDocsQuery(\"field 'title' not found\")");
   }
@@ -87,7 +87,7 @@ public class TestMatchNoDocsQuery extends LuceneTestCase {
     assertEquals(query.toString(), "key:one MatchNoDocsQuery(\"field not found\")");
     assertEquals(searcher.count(query), 1);
     hits = searcher.search(query, 1000).scoreDocs;
-    Query rewrite = query.rewrite(ir);
+    Query rewrite = query.rewrite(searcher);
     assertEquals(1, hits.length);
     assertEquals(rewrite.toString(), "key:one");
 
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java b/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java
index b62d1ec69f1..33acb57c8a5 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java
@@ -499,7 +499,7 @@ public class TestMatchesIterator extends MatchesTestBase {
     SeekCountingLeafReader reader = new SeekCountingLeafReader(getOnlyLeafReader(this.reader));
     this.searcher = new IndexSearcher(reader);
     Query query = new PrefixQuery(new Term(FIELD_WITH_OFFSETS, "w"));
-    Weight w = searcher.createWeight(query.rewrite(reader), ScoreMode.COMPLETE, 1);
+    Weight w = searcher.createWeight(query.rewrite(searcher), ScoreMode.COMPLETE, 1);
 
     // docs 0-3 match several different terms here, but we only seek to the first term and
     // then short-cut return; other terms are ignored until we try and iterate over matches
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java
index f42a576ce54..905b43b93ed 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java
@@ -29,6 +29,7 @@ public class TestNGramPhraseQuery extends LuceneTestCase {
 
   private static IndexReader reader;
   private static Directory directory;
+  private static IndexSearcher searcher;
 
   @BeforeClass
   public static void beforeClass() throws Exception {
@@ -36,6 +37,7 @@ public class TestNGramPhraseQuery extends LuceneTestCase {
     RandomIndexWriter writer = new RandomIndexWriter(random(), directory);
     writer.close();
     reader = DirectoryReader.open(directory);
+    searcher = new IndexSearcher(reader);
   }
 
   @AfterClass
@@ -50,8 +52,8 @@ public class TestNGramPhraseQuery extends LuceneTestCase {
     // bi-gram test ABC => AB/BC => AB/BC
     NGramPhraseQuery pq1 = new NGramPhraseQuery(2, new PhraseQuery("f", "AB", "BC"));
 
-    Query q = pq1.rewrite(reader);
-    assertSame(q.rewrite(reader), q);
+    Query q = pq1.rewrite(searcher);
+    assertSame(q.rewrite(searcher), q);
     PhraseQuery rewritten1 = (PhraseQuery) q;
     assertArrayEquals(new Term[] {new Term("f", "AB"), new Term("f", "BC")}, rewritten1.getTerms());
     assertArrayEquals(new int[] {0, 1}, rewritten1.getPositions());
@@ -59,7 +61,7 @@ public class TestNGramPhraseQuery extends LuceneTestCase {
     // bi-gram test ABCD => AB/BC/CD => AB//CD
     NGramPhraseQuery pq2 = new NGramPhraseQuery(2, new PhraseQuery("f", "AB", "BC", "CD"));
 
-    q = pq2.rewrite(reader);
+    q = pq2.rewrite(searcher);
     assertTrue(q instanceof PhraseQuery);
     assertNotSame(pq2, q);
     PhraseQuery rewritten2 = (PhraseQuery) q;
@@ -70,7 +72,7 @@ public class TestNGramPhraseQuery extends LuceneTestCase {
     NGramPhraseQuery pq3 =
         new NGramPhraseQuery(3, new PhraseQuery("f", "ABC", "BCD", "CDE", "DEF", "EFG", "FGH"));
 
-    q = pq3.rewrite(reader);
+    q = pq3.rewrite(searcher);
     assertTrue(q instanceof PhraseQuery);
     assertNotSame(pq3, q);
     PhraseQuery rewritten3 = (PhraseQuery) q;
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java
index aa2f3c89212..03b58571086 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java
@@ -139,10 +139,10 @@ public class TestNeedsScores extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      Query in2 = in.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      Query in2 = in.rewrite(indexSearcher);
       if (in2 == in) {
-        return super.rewrite(reader);
+        return super.rewrite(indexSearcher);
       } else {
         return new AssertNeedsScores(in2, value);
       }
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java
index da93b3a1951..f721f5e4fe2 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java
@@ -567,7 +567,7 @@ public class TestPhraseQuery extends LuceneTestCase {
   /* test that a single term is rewritten to a term query */
   public void testRewrite() throws IOException {
     PhraseQuery pq = new PhraseQuery("foo", "bar");
-    Query rewritten = pq.rewrite(searcher.getIndexReader());
+    Query rewritten = pq.rewrite(searcher);
     assertTrue(rewritten instanceof TermQuery);
   }
 
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestQueryRewriteBackwardsCompatibility.java b/lucene/core/src/test/org/apache/lucene/search/TestQueryRewriteBackwardsCompatibility.java
new file mode 100644
index 00000000000..a9534b7f191
--- /dev/null
+++ b/lucene/core/src/test/org/apache/lucene/search/TestQueryRewriteBackwardsCompatibility.java
@@ -0,0 +1,269 @@
+/*
+ * 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.lucene.search;
+
+import java.io.IOException;
+import java.util.Objects;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.tests.index.RandomIndexWriter;
+import org.apache.lucene.tests.util.LuceneTestCase;
+
+public class TestQueryRewriteBackwardsCompatibility extends LuceneTestCase {
+
+  public void testQueryRewriteNoOverrides() throws IOException {
+    Directory directory = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), directory, newIndexWriterConfig());
+    IndexReader reader = w.getReader();
+    w.close();
+    IndexSearcher searcher = newSearcher(reader);
+    Query queryNoOverrides = new TestQueryNoOverrides();
+    assertSame(queryNoOverrides, searcher.rewrite(queryNoOverrides));
+    assertSame(queryNoOverrides, queryNoOverrides.rewrite(searcher));
+    assertSame(queryNoOverrides, queryNoOverrides.rewrite(reader));
+    reader.close();
+    directory.close();
+  }
+
+  public void testSingleQueryRewrite() throws IOException {
+    Directory directory = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), directory, newIndexWriterConfig());
+    IndexReader reader = w.getReader();
+    w.close();
+    IndexSearcher searcher = newSearcher(reader);
+
+    RewriteCountingQuery oldQuery = new OldQuery(null);
+    RewriteCountingQuery newQuery = new NewQuery(null);
+
+    oldQuery.rewrite(searcher);
+    oldQuery.rewrite(reader);
+
+    newQuery.rewrite(searcher);
+    newQuery.rewrite(reader);
+
+    assertEquals(2, oldQuery.rewriteCount);
+    assertEquals(2, newQuery.rewriteCount);
+    reader.close();
+    directory.close();
+  }
+
+  public void testNestedQueryRewrite() throws IOException {
+    Directory dir = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), dir, newIndexWriterConfig());
+    IndexReader reader = w.getReader();
+    w.close();
+    IndexSearcher searcher = newSearcher(reader);
+
+    RewriteCountingQuery query = random().nextBoolean() ? new NewQuery(null) : new OldQuery(null);
+
+    for (int i = 0; i < 5 + random().nextInt(5); i++) {
+      query = random().nextBoolean() ? new NewQuery(query) : new OldQuery(query);
+    }
+
+    query.rewrite(searcher);
+    query.rewrite(reader);
+
+    RewriteCountingQuery innerQuery = query;
+    while (innerQuery != null) {
+      assertEquals(2, innerQuery.rewriteCount);
+      innerQuery = innerQuery.getInnerQuery();
+    }
+    reader.close();
+    dir.close();
+  }
+
+  public void testRewriteQueryInheritance() throws IOException {
+    Directory directory = newDirectory();
+    RandomIndexWriter w = new RandomIndexWriter(random(), directory, newIndexWriterConfig());
+    IndexReader reader = w.getReader();
+    w.close();
+    IndexSearcher searcher = newSearcher(reader);
+    NewRewritableCallingSuper oneRewrite = new NewRewritableCallingSuper();
+    NewRewritableCallingSuper twoRewrites = new OldNewRewritableCallingSuper();
+    NewRewritableCallingSuper threeRewrites = new OldOldNewRewritableCallingSuper();
+
+    searcher.rewrite(oneRewrite);
+    searcher.rewrite(twoRewrites);
+    searcher.rewrite(threeRewrites);
+    assertEquals(1, oneRewrite.rewriteCount);
+    assertEquals(2, twoRewrites.rewriteCount);
+    assertEquals(3, threeRewrites.rewriteCount);
+
+    reader.close();
+    directory.close();
+  }
+
+  private static class NewRewritableCallingSuper extends RewriteCountingQuery {
+
+    @Override
+    public Query rewrite(IndexSearcher searcher) throws IOException {
+      rewriteCount++;
+      return super.rewrite(searcher);
+    }
+
+    @Override
+    public String toString(String field) {
+      return "NewRewritableCallingSuper";
+    }
+
+    @Override
+    public void visit(QueryVisitor visitor) {}
+
+    @Override
+    public boolean equals(Object obj) {
+      return obj instanceof NewRewritableCallingSuper;
+    }
+
+    @Override
+    public int hashCode() {
+      return 1;
+    }
+
+    @Override
+    RewriteCountingQuery getInnerQuery() {
+      return null;
+    }
+  }
+
+  private static class OldNewRewritableCallingSuper extends NewRewritableCallingSuper {
+    @Override
+    public Query rewrite(IndexReader reader) throws IOException {
+      rewriteCount++;
+      return super.rewrite(reader);
+    }
+  }
+
+  private static class OldOldNewRewritableCallingSuper extends OldNewRewritableCallingSuper {
+    @Override
+    public Query rewrite(IndexReader reader) throws IOException {
+      rewriteCount++;
+      return super.rewrite(reader);
+    }
+  }
+
+  private abstract static class RewriteCountingQuery extends Query {
+    int rewriteCount = 0;
+
+    abstract RewriteCountingQuery getInnerQuery();
+  }
+
+  private static class OldQuery extends RewriteCountingQuery {
+    private final RewriteCountingQuery optionalSubQuery;
+
+    private OldQuery(RewriteCountingQuery optionalSubQuery) {
+      this.optionalSubQuery = optionalSubQuery;
+    }
+
+    @Override
+    public Query rewrite(IndexReader reader) throws IOException {
+      if (this.optionalSubQuery != null) {
+        this.optionalSubQuery.rewrite(reader);
+      }
+      rewriteCount++;
+      return this;
+    }
+
+    @Override
+    public String toString(String field) {
+      return "OldQuery";
+    }
+
+    @Override
+    public void visit(QueryVisitor visitor) {}
+
+    @Override
+    public boolean equals(Object obj) {
+      return obj instanceof OldQuery
+          && Objects.equals(((OldQuery) obj).optionalSubQuery, optionalSubQuery);
+    }
+
+    @Override
+    public int hashCode() {
+      return 42 ^ Objects.hash(optionalSubQuery);
+    }
+
+    @Override
+    RewriteCountingQuery getInnerQuery() {
+      return optionalSubQuery;
+    }
+  }
+
+  private static class NewQuery extends RewriteCountingQuery {
+    private final RewriteCountingQuery optionalSubQuery;
+
+    private NewQuery(RewriteCountingQuery optionalSubQuery) {
+      this.optionalSubQuery = optionalSubQuery;
+    }
+
+    @Override
+    public Query rewrite(IndexSearcher searcher) throws IOException {
+      if (this.optionalSubQuery != null) {
+        this.optionalSubQuery.rewrite(searcher);
+      }
+      rewriteCount++;
+      return this;
+    }
+
+    @Override
+    public String toString(String field) {
+      return "NewQuery";
+    }
+
+    @Override
+    public void visit(QueryVisitor visitor) {}
+
+    @Override
+    public boolean equals(Object obj) {
+      return obj instanceof NewQuery
+          && Objects.equals(((NewQuery) obj).optionalSubQuery, optionalSubQuery);
+    }
+
+    @Override
+    public int hashCode() {
+      return 73 ^ Objects.hash(optionalSubQuery);
+    }
+
+    @Override
+    RewriteCountingQuery getInnerQuery() {
+      return optionalSubQuery;
+    }
+  }
+
+  private static class TestQueryNoOverrides extends Query {
+
+    private final int randomHash = random().nextInt();
+
+    @Override
+    public String toString(String field) {
+      return "TestQueryNoOverrides";
+    }
+
+    @Override
+    public void visit(QueryVisitor visitor) {}
+
+    @Override
+    public boolean equals(Object obj) {
+      return obj instanceof TestQueryNoOverrides
+          && randomHash == ((TestQueryNoOverrides) obj).randomHash;
+    }
+
+    @Override
+    public int hashCode() {
+      return randomHash;
+    }
+  }
+}
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java
index 936ae8f5834..abc6d7138f3 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java
@@ -950,12 +950,12 @@ public class TestWANDScorer extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      Query rewritten = query.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      Query rewritten = query.rewrite(indexSearcher);
       if (rewritten != query) {
         return new MaxScoreWrapperQuery(rewritten, maxRange, maxScore);
       }
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
 
     @Override
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java
index a4d47aa8c12..9fe4b15b907 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java
@@ -24,11 +24,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.BoostQuery;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.MatchAllDocsQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
@@ -100,8 +100,8 @@ public final class DrillDownQuery extends Query {
 
   /**
    * Creates a new {@code DrillDownQuery} over the given base query. Can be {@code null}, in which
-   * case the result {@link Query} from {@link #rewrite(IndexReader)} will be a pure browsing query,
-   * filtering on the added categories only.
+   * case the result {@link Query} from {@link Query#rewrite(IndexSearcher)} will be a pure browsing
+   * query, filtering on the added categories only.
    */
   public DrillDownQuery(FacetsConfig config, Query baseQuery) {
     this.baseQuery = baseQuery;
@@ -156,7 +156,7 @@ public final class DrillDownQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader r) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     BooleanQuery rewritten = getBooleanQuery();
     if (rewritten.clauses().isEmpty()) {
       return new MatchAllDocsQuery();
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java
index 81643019ad9..88850df057c 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java
@@ -24,7 +24,6 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 import org.apache.lucene.facet.DrillSidewaysScorer.DocsAndCost;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.BulkScorer;
 import org.apache.lucene.search.ConstantScoreScorer;
@@ -80,8 +79,8 @@ class DrillSidewaysQuery extends Query {
   }
 
   /**
-   * Needed for {@link #rewrite(IndexReader)}. Ensures the same "managed" lists get used since
-   * {@link DrillSideways} accesses references to these through the original {@code
+   * Needed for {@link Query#rewrite(IndexSearcher)}. Ensures the same "managed" lists get used
+   * since {@link DrillSideways} accesses references to these through the original {@code
    * DrillSidewaysQuery}.
    */
   private DrillSidewaysQuery(
@@ -107,17 +106,17 @@ class DrillSidewaysQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     Query newQuery = baseQuery;
     while (true) {
-      Query rewrittenQuery = newQuery.rewrite(reader);
+      Query rewrittenQuery = newQuery.rewrite(indexSearcher);
       if (rewrittenQuery == newQuery) {
         break;
       }
       newQuery = rewrittenQuery;
     }
     if (newQuery == baseQuery) {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     } else {
       return new DrillSidewaysQuery(
           newQuery,
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java
index bf188a9d80f..3824baca4d3 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.util.Objects;
 import org.apache.lucene.facet.MultiDoubleValues;
 import org.apache.lucene.facet.MultiDoubleValuesSource;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.ConstantScoreScorer;
 import org.apache.lucene.search.ConstantScoreWeight;
@@ -154,14 +153,14 @@ public final class DoubleRange extends Range {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
       if (fastMatchQuery != null) {
-        final Query fastMatchRewritten = fastMatchQuery.rewrite(reader);
+        final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher);
         if (fastMatchRewritten != fastMatchQuery) {
           return new ValueSourceQuery(range, fastMatchRewritten, valueSource);
         }
       }
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
 
     @Override
@@ -252,14 +251,14 @@ public final class DoubleRange extends Range {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
       if (fastMatchQuery != null) {
-        final Query fastMatchRewritten = fastMatchQuery.rewrite(reader);
+        final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher);
         if (fastMatchRewritten != fastMatchQuery) {
           return new MultiValueSourceQuery(range, fastMatchRewritten, valueSource);
         }
       }
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
 
     @Override
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java
index 63e99190437..6796780d010 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.util.Objects;
 import org.apache.lucene.facet.MultiLongValues;
 import org.apache.lucene.facet.MultiLongValuesSource;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.ConstantScoreScorer;
 import org.apache.lucene.search.ConstantScoreWeight;
@@ -141,14 +140,14 @@ public final class LongRange extends Range {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
       if (fastMatchQuery != null) {
-        final Query fastMatchRewritten = fastMatchQuery.rewrite(reader);
+        final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher);
         if (fastMatchRewritten != fastMatchQuery) {
           return new ValueSourceQuery(range, fastMatchRewritten, valueSource);
         }
       }
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
 
     @Override
@@ -239,14 +238,14 @@ public final class LongRange extends Range {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
       if (fastMatchQuery != null) {
-        final Query fastMatchRewritten = fastMatchQuery.rewrite(reader);
+        final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher);
         if (fastMatchRewritten != fastMatchQuery) {
           return new MultiValueSourceQuery(range, fastMatchRewritten, valuesSource);
         }
       }
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
 
     @Override
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java
index fdac9935eee..d606009d79f 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java
@@ -255,7 +255,8 @@ public class TestDrillDownQuery extends FacetTestCase {
   public void testNoDrillDown() throws Exception {
     Query base = new MatchAllDocsQuery();
     DrillDownQuery q = new DrillDownQuery(config, base);
-    Query rewrite = q.rewrite(reader).rewrite(reader);
+    IndexSearcher searcher = newSearcher(reader);
+    Query rewrite = q.rewrite(searcher).rewrite(searcher);
     assertEquals(base, rewrite);
   }
 
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java
index eb12c2b42ee..1280e2f7511 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java
@@ -740,7 +740,7 @@ public class TestDrillSideways extends FacetTestCase {
     Query baseQuery =
         new TermQuery(new Term("content", "foo")) {
           @Override
-          public Query rewrite(IndexReader reader) {
+          public Query rewrite(IndexSearcher indexSearcher) {
             // return a new instance, forcing the DrillDownQuery to also rewrite itself, exposing
             // the bug in LUCENE-9988:
             return new TermQuery(getTerm());
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java
index 97cf11c8e1a..ca86e83e41b 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java
@@ -1450,12 +1450,12 @@ public class TestRangeFacetCounts extends FacetTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      final Query inRewritten = in.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      final Query inRewritten = in.rewrite(indexSearcher);
       if (in != inRewritten) {
         return new UsedQuery(inRewritten, used);
       }
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
 
     @Override
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java
index da77a97ac9f..7fbe6fbd080 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java
@@ -250,7 +250,7 @@ public class WeightedSpanTermExtractor {
       if (query instanceof MultiTermQuery) {
         rewritten = MultiTermQuery.SCORING_BOOLEAN_REWRITE.rewrite(reader, (MultiTermQuery) query);
       } else {
-        rewritten = origQuery.rewrite(reader);
+        rewritten = origQuery.rewrite(new IndexSearcher(reader));
       }
       if (rewritten != origQuery) {
         // only rewrite once and then flatten again - the rewritten query could have a special
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java
index 0dee795ebc2..615db5ecd5f 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java
@@ -1252,11 +1252,11 @@ public class UnifiedHighlighter {
 
   /**
    * When highlighting phrases accurately, we need to know which {@link SpanQuery}'s need to have
-   * {@link Query#rewrite(IndexReader)} called on them. It helps performance to avoid it if it's not
-   * needed. This method will be invoked on all SpanQuery instances recursively. If you have custom
-   * SpanQuery queries then override this to check instanceof and provide a definitive answer. If
-   * the query isn't your custom one, simply return null to have the default rules apply, which
-   * govern the ones included in Lucene.
+   * {@link Query#rewrite(IndexSearcher)} called on them. It helps performance to avoid it if it's
+   * not needed. This method will be invoked on all SpanQuery instances recursively. If you have
+   * custom SpanQuery queries then override this to check instanceof and provide a definitive
+   * answer. If the query isn't your custom one, simply return null to have the default rules apply,
+   * which govern the ones included in Lucene.
    */
   protected Boolean requiresRewrite(SpanQuery spanQuery) {
     return null;
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java
index ff5a11c47d6..851197e42d5 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java
@@ -33,6 +33,7 @@ import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.BoostQuery;
 import org.apache.lucene.search.ConstantScoreQuery;
 import org.apache.lucene.search.DisjunctionMaxQuery;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.MultiTermQuery;
 import org.apache.lucene.search.PhraseQuery;
 import org.apache.lucene.search.Query;
@@ -65,8 +66,14 @@ public class FieldQuery {
       throws IOException {
     this.fieldMatch = fieldMatch;
     Set<Query> flatQueries = new LinkedHashSet<>();
-    flatten(query, reader, flatQueries, 1f);
-    saveTerms(flatQueries, reader);
+    IndexSearcher searcher;
+    if (reader == null) {
+      searcher = null;
+    } else {
+      searcher = new IndexSearcher(reader);
+    }
+    flatten(query, searcher, flatQueries, 1f);
+    saveTerms(flatQueries, searcher);
     Collection<Query> expandQueries = expand(flatQueries);
 
     for (Query flatQuery : expandQueries) {
@@ -96,7 +103,7 @@ public class FieldQuery {
   }
 
   protected void flatten(
-      Query sourceQuery, IndexReader reader, Collection<Query> flatQueries, float boost)
+      Query sourceQuery, IndexSearcher searcher, Collection<Query> flatQueries, float boost)
       throws IOException {
     while (sourceQuery instanceof BoostQuery) {
       BoostQuery bq = (BoostQuery) sourceQuery;
@@ -107,13 +114,13 @@ public class FieldQuery {
       BooleanQuery bq = (BooleanQuery) sourceQuery;
       for (BooleanClause clause : bq) {
         if (!clause.isProhibited()) {
-          flatten(clause.getQuery(), reader, flatQueries, boost);
+          flatten(clause.getQuery(), searcher, flatQueries, boost);
         }
       }
     } else if (sourceQuery instanceof DisjunctionMaxQuery) {
       DisjunctionMaxQuery dmq = (DisjunctionMaxQuery) sourceQuery;
       for (Query query : dmq) {
-        flatten(query, reader, flatQueries, boost);
+        flatten(query, searcher, flatQueries, boost);
       }
     } else if (sourceQuery instanceof TermQuery) {
       if (boost != 1f) {
@@ -123,7 +130,7 @@ public class FieldQuery {
     } else if (sourceQuery instanceof SynonymQuery) {
       SynonymQuery synQuery = (SynonymQuery) sourceQuery;
       for (Term term : synQuery.getTerms()) {
-        flatten(new TermQuery(term), reader, flatQueries, boost);
+        flatten(new TermQuery(term), searcher, flatQueries, boost);
       }
     } else if (sourceQuery instanceof PhraseQuery) {
       PhraseQuery pq = (PhraseQuery) sourceQuery;
@@ -135,28 +142,28 @@ public class FieldQuery {
     } else if (sourceQuery instanceof ConstantScoreQuery) {
       final Query q = ((ConstantScoreQuery) sourceQuery).getQuery();
       if (q != null) {
-        flatten(q, reader, flatQueries, boost);
+        flatten(q, searcher, flatQueries, boost);
       }
     } else if (sourceQuery instanceof FunctionScoreQuery) {
       final Query q = ((FunctionScoreQuery) sourceQuery).getWrappedQuery();
       if (q != null) {
-        flatten(q, reader, flatQueries, boost);
+        flatten(q, searcher, flatQueries, boost);
       }
-    } else if (reader != null) {
+    } else if (searcher != null) {
       Query query = sourceQuery;
       Query rewritten;
       if (sourceQuery instanceof MultiTermQuery) {
         rewritten =
             new MultiTermQuery.TopTermsScoringBooleanQueryRewrite(MAX_MTQ_TERMS)
-                .rewrite(reader, (MultiTermQuery) query);
+                .rewrite(searcher.getIndexReader(), (MultiTermQuery) query);
       } else {
-        rewritten = query.rewrite(reader);
+        rewritten = query.rewrite(searcher);
       }
       if (rewritten != query) {
         // only rewrite once and then flatten again - the rewritten query could have a speacial
         // treatment
         // if this method is overwritten in a subclass.
-        flatten(rewritten, reader, flatQueries, boost);
+        flatten(rewritten, searcher, flatQueries, boost);
       }
       // if the query is already rewritten we discard it
     }
@@ -311,7 +318,7 @@ public class FieldQuery {
    *      - fieldMatch==false
    *          termSetMap=Map<null,Set<"john","lennon">>
    */
-  void saveTerms(Collection<Query> flatQueries, IndexReader reader) throws IOException {
+  void saveTerms(Collection<Query> flatQueries, IndexSearcher searcher) throws IOException {
     for (Query query : flatQueries) {
       while (query instanceof BoostQuery) {
         query = ((BoostQuery) query).getQuery();
@@ -320,8 +327,8 @@ public class FieldQuery {
       if (query instanceof TermQuery) termSet.add(((TermQuery) query).getTerm().text());
       else if (query instanceof PhraseQuery) {
         for (Term term : ((PhraseQuery) query).getTerms()) termSet.add(term.text());
-      } else if (query instanceof MultiTermQuery && reader != null) {
-        BooleanQuery mtqTerms = (BooleanQuery) query.rewrite(reader);
+      } else if (query instanceof MultiTermQuery && searcher != null) {
+        BooleanQuery mtqTerms = (BooleanQuery) query.rewrite(searcher);
         for (BooleanClause clause : mtqTerms) {
           termSet.add(((TermQuery) clause.getQuery()).getTerm().text());
         }
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java
index cb1e640f355..1664eb4be67 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java
@@ -261,7 +261,7 @@ public class TestHighlighter extends BaseTokenStreamTestCase implements Formatte
         new Query() {
 
           @Override
-          public Query rewrite(IndexReader reader) throws IOException {
+          public Query rewrite(IndexSearcher indexSearcher) throws IOException {
             CommonTermsQuery query = new CommonTermsQuery(Occur.MUST, Occur.SHOULD, 3);
             query.add(new Term(FIELD_NAME, "this")); // stop-word
             query.add(new Term(FIELD_NAME, "long"));
@@ -2223,7 +2223,7 @@ public class TestHighlighter extends BaseTokenStreamTestCase implements Formatte
     searcher = newSearcher(reader);
     // for any multi-term queries to work (prefix, wildcard, range,fuzzy etc)
     // you must use a rewritten query!
-    query = unReWrittenQuery.rewrite(reader);
+    query = unReWrittenQuery.rewrite(searcher);
     if (VERBOSE) System.out.println("Searching for: " + query.toString(FIELD_NAME));
     hits = searcher.search(query, 1000);
   }
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java
index 97e0baf6e91..37235bdb611 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java
@@ -21,9 +21,9 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.Objects;
 import org.apache.lucene.analysis.TokenStream;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BoostQuery;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 import org.apache.lucene.search.TermQuery;
@@ -167,7 +167,7 @@ public class TestHighlightCustomQuery extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
       return new TermQuery(term);
     }
 
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java
index f831fbf77a7..6cc524a9fac 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java
@@ -1619,7 +1619,7 @@ public class TestUnifiedHighlighter extends LuceneTestCase {
                   }
 
                   @Override
-                  public Query rewrite(IndexReader reader) {
+                  public Query rewrite(IndexSearcher indexSearcher) {
                     return this;
                   }
 
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java
index 4f7bd056ca1..4aabf26d45b 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java
@@ -1111,8 +1111,8 @@ public class TestUnifiedHighlighterMTQ extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      Query newOriginalQuery = originalQuery.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      Query newOriginalQuery = originalQuery.rewrite(indexSearcher);
       if (newOriginalQuery != originalQuery) {
         return new MyWrapperSpanQuery((SpanQuery) newOriginalQuery);
       }
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java
index 8116ece1c1c..9f189a215b8 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java
@@ -658,8 +658,8 @@ public class TestUnifiedHighlighterStrictPhrases extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      Query newWrapped = wrapped.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      Query newWrapped = wrapped.rewrite(indexSearcher);
       if (newWrapped != wrapped) {
         return new MyQuery(newWrapped);
       }
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java
index 8542a45aab7..9a2f8a9e4fa 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java
@@ -21,7 +21,9 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
-import org.apache.lucene.analysis.*;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Tokenizer;
 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
 import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute;
@@ -37,6 +39,7 @@ import org.apache.lucene.index.IndexWriterConfig.OpenMode;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BoostQuery;
 import org.apache.lucene.search.DisjunctionMaxQuery;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.PhraseQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
@@ -56,6 +59,7 @@ public abstract class AbstractTestCase extends LuceneTestCase {
   protected Analyzer analyzerB;
   protected Analyzer analyzerK;
   protected IndexReader reader;
+  protected IndexSearcher searcher;
 
   protected static final String[] shortMVValues = {
     "", "", "a b c", "", // empty data in multi valued field
@@ -343,6 +347,7 @@ public abstract class AbstractTestCase extends LuceneTestCase {
     writer.close();
     if (reader != null) reader.close();
     reader = DirectoryReader.open(dir);
+    searcher = newSearcher(reader);
   }
 
   // make 1 doc with multi valued & not analyzed field
@@ -363,6 +368,7 @@ public abstract class AbstractTestCase extends LuceneTestCase {
     writer.close();
     if (reader != null) reader.close();
     reader = DirectoryReader.open(dir);
+    searcher = newSearcher(reader);
   }
 
   protected void makeIndexShortMV() throws Exception {
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java
index 42fec6dba55..6538c0d2985 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java
@@ -63,7 +63,7 @@ public class TestFieldQuery extends AbstractTestCase {
 
     FieldQuery fq = new FieldQuery(booleanQuery, true, true);
     Set<Query> flatQueries = new HashSet<>();
-    fq.flatten(booleanQuery, reader, flatQueries, 1f);
+    fq.flatten(booleanQuery, searcher, flatQueries, 1f);
     assertCollectionQueries(flatQueries, tq(boost, "A"), tq(boost, "B"), tq(boost, "C"));
   }
 
@@ -73,7 +73,7 @@ public class TestFieldQuery extends AbstractTestCase {
     query = new BoostQuery(query, boost);
     FieldQuery fq = new FieldQuery(query, true, true);
     Set<Query> flatQueries = new HashSet<>();
-    fq.flatten(query, reader, flatQueries, 1f);
+    fq.flatten(query, searcher, flatQueries, 1f);
     assertCollectionQueries(flatQueries, tq(boost, "A"), tq(boost, "B"), pqF(boost, "C", "D"));
   }
 
@@ -87,7 +87,7 @@ public class TestFieldQuery extends AbstractTestCase {
 
     FieldQuery fq = new FieldQuery(booleanQuery, true, true);
     Set<Query> flatQueries = new HashSet<>();
-    fq.flatten(booleanQuery, reader, flatQueries, 1f);
+    fq.flatten(booleanQuery, searcher, flatQueries, 1f);
     assertCollectionQueries(flatQueries, tq(boost, "A"), pqF(boost, "B", "C"));
   }
 
@@ -99,7 +99,7 @@ public class TestFieldQuery extends AbstractTestCase {
 
     FieldQuery fq = new FieldQuery(query.build(), true, true);
     Set<Query> flatQueries = new HashSet<>();
-    fq.flatten(query.build(), reader, flatQueries, 1f);
+    fq.flatten(query.build(), searcher, flatQueries, 1f);
     assertCollectionQueries(flatQueries, tq("AA"), pqF("BC", "CD"), pqF("EF", "FG", "GH"));
   }
 
@@ -107,7 +107,7 @@ public class TestFieldQuery extends AbstractTestCase {
     Query query = pqF("A");
     FieldQuery fq = new FieldQuery(query, true, true);
     Set<Query> flatQueries = new HashSet<>();
-    fq.flatten(query, reader, flatQueries, 1f);
+    fq.flatten(query, searcher, flatQueries, 1f);
     assertCollectionQueries(flatQueries, tq("A"));
   }
 
@@ -950,7 +950,7 @@ public class TestFieldQuery extends AbstractTestCase {
     query = new BoostQuery(query, boost);
     FieldQuery fq = new FieldQuery(query, true, true);
     Set<Query> flatQueries = new HashSet<>();
-    fq.flatten(query, reader, flatQueries, 1f);
+    fq.flatten(query, searcher, flatQueries, 1f);
     assertCollectionQueries(flatQueries, tq(boost, "A"));
   }
 }
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java
index 9ba6daee284..64f5e5ba116 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java
@@ -18,7 +18,6 @@
 package org.apache.lucene.search.join;
 
 import java.io.IOException;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.ReaderUtil;
 import org.apache.lucene.search.DocIdSetIterator;
@@ -88,12 +87,12 @@ public class ParentChildrenBlockJoinQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query childRewrite = childQuery.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query childRewrite = childQuery.rewrite(indexSearcher);
     if (childRewrite != childQuery) {
       return new ParentChildrenBlockJoinQuery(parentFilter, childRewrite, parentDocId);
     } else {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
   }
 
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java
index 42c41efcefa..3f2a9e76c54 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Locale;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.search.Explanation;
@@ -305,12 +304,12 @@ public class ToChildBlockJoinQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query parentRewrite = parentQuery.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query parentRewrite = parentQuery.rewrite(indexSearcher);
     if (parentRewrite != parentQuery) {
       return new ToChildBlockJoinQuery(parentRewrite, parentsFilter);
     } else {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
   }
 
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java
index 87481f03a88..6134cd0e1dd 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java
@@ -22,7 +22,6 @@ import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Locale;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.ConstantScoreQuery;
@@ -441,12 +440,12 @@ public class ToParentBlockJoinQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query childRewrite = childQuery.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query childRewrite = childQuery.rewrite(indexSearcher);
     if (childRewrite != childQuery) {
       return new ToParentBlockJoinQuery(childRewrite, parentsFilter, scoreMode);
     } else {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
   }
 
diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java b/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java
index 9936d692415..fa552e65d3f 100644
--- a/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java
+++ b/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java
@@ -152,7 +152,7 @@ public final class SearchImpl extends LukeModel implements Search {
 
     if (rewrite) {
       try {
-        query = query.rewrite(reader);
+        query = query.rewrite(searcher);
       } catch (IOException e) {
         throw new LukeException(
             String.format(Locale.ENGLISH, "Failed to rewrite query: %s", query.toString()), e);
diff --git a/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java b/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java
index e561346f8cf..ca63678fd2b 100644
--- a/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java
+++ b/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java
@@ -499,12 +499,12 @@ public class TestDiversifiedTopDocsCollector extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      Query rewritten = query.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      Query rewritten = query.rewrite(indexSearcher);
       if (rewritten != query) {
         return new DocValueScoreQuery(rewritten, scoreField);
       }
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     }
 
     @Override
diff --git a/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java b/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java
index 2af23b4a561..a97d1054c4c 100644
--- a/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java
+++ b/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.monitor;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.*;
 import org.apache.lucene.search.Matches;
@@ -34,10 +33,10 @@ class ForceNoBulkScoringQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query rewritten = inner.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    Query rewritten = inner.rewrite(indexSearcher);
     if (rewritten != inner) return new ForceNoBulkScoringQuery(rewritten);
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java b/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java
index 65017e73247..548c417aafe 100644
--- a/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java
+++ b/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java
@@ -22,9 +22,9 @@ import java.util.HashMap;
 import java.util.Map;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.queryparser.classic.ParseException;
 import org.apache.lucene.queryparser.classic.QueryParser;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 import org.apache.lucene.tests.util.LuceneTestCase;
@@ -65,7 +65,7 @@ public abstract class MonitorTestBase extends LuceneTestCase {
   public static class ThrowOnRewriteQuery extends Query {
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
       throw new IOException("Error rewriting");
     }
 
diff --git a/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java b/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java
index 28f96c760b3..4f5011ba17e 100644
--- a/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java
+++ b/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java
@@ -67,7 +67,7 @@ public class TestForceNoBulkScoringQuery extends LuceneTestCase {
 
       assertEquals(q.getWrappedQuery(), pq);
 
-      Query rewritten = q.rewrite(reader);
+      Query rewritten = q.rewrite(newSearcher(reader));
       assertTrue(rewritten instanceof ForceNoBulkScoringQuery);
 
       Query inner = ((ForceNoBulkScoringQuery) rewritten).getWrappedQuery();
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java
index 46a7f45069a..b6ff82dce38 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java
@@ -30,6 +30,7 @@ import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.BoostQuery;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.MatchNoDocsQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
@@ -101,7 +102,8 @@ public class CommonTermsQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    IndexReader reader = indexSearcher.getIndexReader();
     if (this.terms.isEmpty()) {
       return new MatchNoDocsQuery("CommonTermsQuery with no terms");
     } else if (this.terms.size() == 1) {
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java
index f5f03d20291..449188091bd 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.queries.function;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.DoubleValues;
@@ -122,8 +121,8 @@ public final class FunctionScoreQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query rewritten = in.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    Query rewritten = in.rewrite(indexSearcher);
     if (rewritten == in) {
       return this;
     }
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java
index 7ba1bb00b5e..159d30c8e54 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java
@@ -22,9 +22,9 @@ import java.util.Arrays;
 import java.util.Objects;
 import java.util.Set;
 import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 
@@ -57,8 +57,8 @@ public class MoreLikeThisQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    MoreLikeThis mlt = new MoreLikeThis(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    MoreLikeThis mlt = new MoreLikeThis(indexSearcher.getIndexReader());
 
     mlt.setFieldNames(moreLikeFields);
     mlt.setAnalyzer(analyzer);
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java
index a782901f932..d4dd52b4620 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.queries.payloads;
 import java.io.IOException;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.Term;
@@ -83,12 +82,12 @@ public class PayloadScoreQuery extends SpanQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query matchRewritten = wrappedQuery.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    Query matchRewritten = wrappedQuery.rewrite(indexSearcher);
     if (wrappedQuery != matchRewritten && matchRewritten instanceof SpanQuery) {
       return new PayloadScoreQuery((SpanQuery) matchRewritten, function, decoder, includeSpanScore);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java
index 1d3c13ed9cd..ef04a8dccd0 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.PostingsEnum;
 import org.apache.lucene.index.Term;
@@ -116,13 +115,13 @@ public class SpanPayloadCheckQuery extends SpanQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query matchRewritten = match.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    Query matchRewritten = match.rewrite(indexSearcher);
     if (match != matchRewritten && matchRewritten instanceof SpanQuery) {
       return new SpanPayloadCheckQuery(
           (SpanQuery) matchRewritten, payloadToMatch, payloadType, operation);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java
index 500f9aad456..038a2e3742d 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java
@@ -18,7 +18,6 @@ package org.apache.lucene.queries.spans;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
@@ -93,13 +92,13 @@ public final class FieldMaskingSpanQuery extends SpanQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    SpanQuery rewritten = (SpanQuery) maskedQuery.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    SpanQuery rewritten = (SpanQuery) maskedQuery.rewrite(indexSearcher);
     if (rewritten != maskedQuery) {
       return new FieldMaskingSpanQuery(rewritten, field);
     }
 
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java
index 680ceea0f78..99412f96406 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java
@@ -20,7 +20,6 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermStates;
@@ -109,9 +108,9 @@ abstract class SpanContainQuery extends SpanQuery implements Cloneable {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    SpanQuery rewrittenBig = (SpanQuery) big.rewrite(reader);
-    SpanQuery rewrittenLittle = (SpanQuery) little.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    SpanQuery rewrittenBig = (SpanQuery) big.rewrite(indexSearcher);
+    SpanQuery rewrittenLittle = (SpanQuery) little.rewrite(indexSearcher);
     if (big != rewrittenBig || little != rewrittenLittle) {
       try {
         SpanContainQuery clone = (SpanContainQuery) super.clone();
@@ -122,7 +121,7 @@ abstract class SpanContainQuery extends SpanQuery implements Cloneable {
         throw new AssertionError(e);
       }
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java
index aa36368270e..882e6c96fb3 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java
@@ -117,8 +117,8 @@ public class SpanMultiTermQueryWrapper<Q extends MultiTermQuery> extends SpanQue
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    return rewriteMethod.rewrite(reader, query);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return rewriteMethod.rewrite(indexSearcher.getIndexReader(), query);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java
index b3f9f8e357b..00318e4bae6 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java
@@ -23,7 +23,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermStates;
@@ -242,12 +241,12 @@ public class SpanNearQuery extends SpanQuery implements Cloneable {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     boolean actuallyRewritten = false;
     List<SpanQuery> rewrittenClauses = new ArrayList<>();
     for (int i = 0; i < clauses.size(); i++) {
       SpanQuery c = clauses.get(i);
-      SpanQuery query = (SpanQuery) c.rewrite(reader);
+      SpanQuery query = (SpanQuery) c.rewrite(indexSearcher);
       actuallyRewritten |= query != c;
       rewrittenClauses.add(query);
     }
@@ -260,7 +259,7 @@ public class SpanNearQuery extends SpanQuery implements Cloneable {
         throw new AssertionError(e);
       }
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java
index fc2f334a4ba..aded21f5f7c 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.queries.spans;
 import java.io.IOException;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermStates;
@@ -224,13 +223,13 @@ public final class SpanNotQuery extends SpanQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    SpanQuery rewrittenInclude = (SpanQuery) include.rewrite(reader);
-    SpanQuery rewrittenExclude = (SpanQuery) exclude.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    SpanQuery rewrittenInclude = (SpanQuery) include.rewrite(indexSearcher);
+    SpanQuery rewrittenExclude = (SpanQuery) exclude.rewrite(indexSearcher);
     if (rewrittenInclude != include || rewrittenExclude != exclude) {
       return new SpanNotQuery(rewrittenInclude, rewrittenExclude, pre, post);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java
index 2b8e1856774..46b14aef92d 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java
@@ -21,7 +21,6 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermStates;
@@ -67,19 +66,19 @@ public final class SpanOrQuery extends SpanQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     SpanOrQuery rewritten = new SpanOrQuery();
     boolean actuallyRewritten = false;
     for (int i = 0; i < clauses.size(); i++) {
       SpanQuery c = clauses.get(i);
-      SpanQuery query = (SpanQuery) c.rewrite(reader);
+      SpanQuery query = (SpanQuery) c.rewrite(indexSearcher);
       actuallyRewritten |= query != c;
       rewritten.addClause(query);
     }
     if (actuallyRewritten) {
       return rewritten;
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java
index 0227a13f3ab..a83969f3fb5 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.queries.spans;
 import java.io.IOException;
 import java.util.Map;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.TermStates;
@@ -113,8 +112,8 @@ public abstract class SpanPositionCheckQuery extends SpanQuery implements Clonea
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    SpanQuery rewritten = (SpanQuery) match.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    SpanQuery rewritten = (SpanQuery) match.rewrite(indexSearcher);
     if (rewritten != match) {
       try {
         SpanPositionCheckQuery clone = (SpanPositionCheckQuery) this.clone();
@@ -125,7 +124,7 @@ public abstract class SpanPositionCheckQuery extends SpanQuery implements Clonea
       }
     }
 
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java b/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java
index 93bed6fe9f5..48a84c105f2 100644
--- a/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java
+++ b/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java
@@ -781,8 +781,8 @@ public class TestValueSources extends LuceneTestCase {
       }
 
       @Override
-      public Query rewrite(IndexReader reader) throws IOException {
-        var rewrite = in.rewrite(reader);
+      public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+        var rewrite = in.rewrite(indexSearcher);
         return rewrite == in ? this : new AssertScoreComputedOnceQuery(rewrite);
       }
 
diff --git a/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java b/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java
index f22a70a0302..8eab12aa7d1 100644
--- a/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java
+++ b/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java
@@ -18,7 +18,6 @@ package org.apache.lucene.queries.spans;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
@@ -50,10 +49,10 @@ public class AssertingSpanQuery extends SpanQuery {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    Query q = in.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    Query q = in.rewrite(indexSearcher);
     if (q == in) {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     } else if (q instanceof SpanQuery) {
       return new AssertingSpanQuery((SpanQuery) q);
     } else {
diff --git a/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java b/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java
index 567bfdf711e..9c98a002582 100644
--- a/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java
+++ b/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java
@@ -164,7 +164,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase {
         new FieldMaskingSpanQuery(
             new SpanTermQuery(new Term("last", "sally")) {
               @Override
-              public Query rewrite(IndexReader reader) {
+              public Query rewrite(IndexSearcher indexSearcher) {
                 return new SpanOrQuery(
                     new SpanTermQuery(new Term("first", "sally")),
                     new SpanTermQuery(new Term("first", "james")));
diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java
index 4dad705b876..339e60a14bd 100644
--- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java
+++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java
@@ -22,7 +22,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.queries.spans.SpanNearQuery;
 import org.apache.lucene.queries.spans.SpanNotQuery;
@@ -256,7 +255,7 @@ public class ComplexPhraseQueryParser extends QueryParser {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
       final Query contents = this.contents[0];
       // ArrayList spanClauses = new ArrayList();
       if (contents instanceof TermQuery
@@ -284,7 +283,7 @@ public class ComplexPhraseQueryParser extends QueryParser {
         // HashSet bclauseterms=new HashSet();
         Query qc = clause.getQuery();
         // Rewrite this clause e.g one* becomes (one OR onerous)
-        qc = new IndexSearcher(reader).rewrite(qc);
+        qc = indexSearcher.rewrite(qc);
         if (clause.getOccur().equals(BooleanClause.Occur.MUST_NOT)) {
           numNegatives++;
         }
diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java
index d739bc022e6..7186aa3cf24 100644
--- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java
+++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java
@@ -17,7 +17,7 @@
 package org.apache.lucene.queryparser.surround.query;
 
 import java.io.IOException;
-import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 
@@ -28,8 +28,8 @@ class DistanceRewriteQuery extends RewriteQuery<DistanceQuery> {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    return srndQuery.getSpanNearQuery(reader, fieldName, qf);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    return srndQuery.getSpanNearQuery(indexSearcher.getIndexReader(), fieldName, qf);
   }
 
   @Override
diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java
index 69005e6dd00..533cf72ce02 100644
--- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java
+++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java
@@ -18,7 +18,7 @@ package org.apache.lucene.queryparser.surround.query;
 
 import java.io.IOException;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 
 abstract class RewriteQuery<SQ extends SrndQuery> extends Query {
@@ -33,7 +33,7 @@ abstract class RewriteQuery<SQ extends SrndQuery> extends Query {
   }
 
   @Override
-  public abstract Query rewrite(IndexReader reader) throws IOException;
+  public abstract Query rewrite(IndexSearcher indexSearcher) throws IOException;
 
   @Override
   public String toString(String field) {
diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java
index 22f1118beb4..4371e5f224f 100644
--- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java
+++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java
@@ -19,9 +19,9 @@ package org.apache.lucene.queryparser.surround.query;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.MatchNoDocsQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
@@ -33,10 +33,10 @@ class SimpleTermRewriteQuery extends RewriteQuery<SimpleTerm> {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     final List<Query> luceneSubQueries = new ArrayList<>();
     srndQuery.visitMatchingTerms(
-        reader,
+        indexSearcher.getIndexReader(),
         fieldName,
         new SimpleTerm.MatchingTermVisitor() {
           @Override
diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java
index ae306da9afc..102360fae87 100644
--- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java
+++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java
@@ -316,7 +316,7 @@ public class TestCoreParser extends LuceneTestCase {
   }
 
   protected Query rewrite(Query q) throws IOException {
-    return q.rewrite(reader());
+    return q.rewrite(searcher());
   }
 
   protected void dumpResults(String qType, Query q, int numDocs) throws IOException {
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java
index 6193d27a99f..ab4cbb05fc9 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java
@@ -38,6 +38,7 @@ import org.apache.lucene.search.BoostAttribute;
 import org.apache.lucene.search.BoostQuery;
 import org.apache.lucene.search.ConstantScoreQuery;
 import org.apache.lucene.search.FuzzyTermsEnum;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
 import org.apache.lucene.search.TermQuery;
@@ -282,7 +283,8 @@ public class FuzzyLikeThisQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    IndexReader reader = indexSearcher.getIndexReader();
     ScoreTermQueue q = new ScoreTermQueue(maxNumTerms);
     // load up the list of possible terms
     for (FieldVals f : fieldVals) {
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java
index 3196f9a6d99..08bb24a846c 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java
@@ -253,7 +253,7 @@ public final class CombinedFieldQuery extends Query implements Accountable {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (terms.length == 0 || fieldAndWeights.isEmpty()) {
       return new BooleanQuery.Builder().build();
     }
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java
index 69e5bd69f83..5a493a00c1a 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java
@@ -22,7 +22,6 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
@@ -125,7 +124,7 @@ public final class CoveringQuery extends Query implements Accountable {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (minimumNumberMatch instanceof LongValuesSource.ConstantLongValuesSource) {
       final long constantMin =
           ((LongValuesSource.ConstantLongValuesSource) minimumNumberMatch).getValue();
@@ -136,7 +135,7 @@ public final class CoveringQuery extends Query implements Accountable {
       BooleanQuery.Builder builder =
           new BooleanQuery.Builder().setMinimumNumberShouldMatch((int) Math.max(constantMin, 1));
       for (Query query : queries) {
-        Query r = query.rewrite(reader);
+        Query r = query.rewrite(indexSearcher);
         builder.add(r, BooleanClause.Occur.SHOULD);
       }
       return builder.build();
@@ -144,14 +143,14 @@ public final class CoveringQuery extends Query implements Accountable {
     Multiset<Query> rewritten = new Multiset<>();
     boolean actuallyRewritten = false;
     for (Query query : queries) {
-      Query r = query.rewrite(reader);
+      Query r = query.rewrite(indexSearcher);
       rewritten.add(r);
       actuallyRewritten |= query != r;
     }
     if (actuallyRewritten) {
       return new CoveringQuery(rewritten, minimumNumberMatch);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java
index 19b885dfed5..837de213d22 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java
@@ -23,7 +23,6 @@ import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.PointValues;
@@ -169,7 +168,7 @@ public abstract class MultiRangeQuery extends Query implements Cloneable {
    * #mergeOverlappingRanges}
    */
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (numDims != 1) {
       return this;
     }
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java
index c4fc7189fe1..bbe8a4970eb 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java
@@ -113,14 +113,14 @@ public class PhraseWildcardQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (phraseTerms.isEmpty()) {
       return NO_MATCH_QUERY;
     }
     if (phraseTerms.size() == 1) {
       return phraseTerms.get(0).getQuery();
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java
index d06c99523bb..7fae86711d8 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexReaderContext;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.PostingsEnum;
@@ -485,7 +484,7 @@ public class TermAutomatonQuery extends Query implements Accountable {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     if (Operations.isEmpty(det)) {
       return new MatchNoDocsQuery();
     }
diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java
index 89506bfa7bf..2b8fca789cb 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java
@@ -81,7 +81,7 @@ public class TestFuzzyLikeThisQuery extends LuceneTestCase {
   public void testClosestEditDistanceMatchComesFirst() throws Throwable {
     FuzzyLikeThisQuery flt = new FuzzyLikeThisQuery(10, analyzer);
     flt.addTerms("smith", "name", 2, 1);
-    Query q = flt.rewrite(searcher.getIndexReader());
+    Query q = flt.rewrite(searcher);
     HashSet<Term> queryTerms = new HashSet<>();
     q.visit(QueryVisitor.termCollector(queryTerms));
     assertTrue("Should have variant smythe", queryTerms.contains(new Term("name", "smythe")));
@@ -98,7 +98,7 @@ public class TestFuzzyLikeThisQuery extends LuceneTestCase {
   public void testMultiWord() throws Throwable {
     FuzzyLikeThisQuery flt = new FuzzyLikeThisQuery(10, analyzer);
     flt.addTerms("jonathin smoth", "name", 2, 1);
-    Query q = flt.rewrite(searcher.getIndexReader());
+    Query q = flt.rewrite(searcher);
     HashSet<Term> queryTerms = new HashSet<>();
     q.visit(QueryVisitor.termCollector(queryTerms));
     assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan")));
@@ -116,7 +116,7 @@ public class TestFuzzyLikeThisQuery extends LuceneTestCase {
     flt.addTerms("jonathin smoth", "name", 2, 1);
     flt.addTerms("jonathin smoth", "this field does not exist", 2, 1);
     // don't fail here just because the field doesn't exits
-    Query q = flt.rewrite(searcher.getIndexReader());
+    Query q = flt.rewrite(searcher);
     HashSet<Term> queryTerms = new HashSet<>();
     q.visit(QueryVisitor.termCollector(queryTerms));
     assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan")));
@@ -132,7 +132,7 @@ public class TestFuzzyLikeThisQuery extends LuceneTestCase {
   public void testNoMatchFirstWordBug() throws Throwable {
     FuzzyLikeThisQuery flt = new FuzzyLikeThisQuery(10, analyzer);
     flt.addTerms("fernando smith", "name", 2, 1);
-    Query q = flt.rewrite(searcher.getIndexReader());
+    Query q = flt.rewrite(searcher);
     HashSet<Term> queryTerms = new HashSet<>();
     q.visit(QueryVisitor.termCollector(queryTerms));
     assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith")));
diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java
index 98d174f806c..3edc18b16a0 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java
@@ -80,7 +80,8 @@ public class TestCoveringQuery extends LuceneTestCase {
     LongValuesSource vs = LongValuesSource.fromIntField("field");
     assertEquals(
         new CoveringQuery(Collections.singleton(tq), vs),
-        new CoveringQuery(Collections.singleton(pq), vs).rewrite(new MultiReader()));
+        new CoveringQuery(Collections.singleton(pq), vs)
+            .rewrite(new IndexSearcher(new MultiReader())));
   }
 
   public void testToString() {
diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java
index b4d1e49445f..0162fe2d3b5 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java
@@ -806,7 +806,7 @@ public class TestMultiRangeQueries extends LuceneTestCase {
         builder2.add(LongPoint.newRangeQuery("point", lower, upper), BooleanClause.Occur.SHOULD);
       }
 
-      MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(reader);
+      MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(searcher);
       BooleanQuery booleanQuery = builder2.build();
       int count = searcher.search(multiRangeQuery, DummyTotalHitCountCollector.createManager());
       int booleanCount = searcher.search(booleanQuery, DummyTotalHitCountCollector.createManager());
@@ -839,7 +839,7 @@ public class TestMultiRangeQueries extends LuceneTestCase {
         builder2.add(LongPoint.newRangeQuery("point", lower, upper), BooleanClause.Occur.SHOULD);
       }
 
-      MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(reader);
+      MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(searcher);
       BooleanQuery booleanQuery = builder2.build();
       int count =
           multiRangeQuery
diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java
index 8598d1efe9b..3d5539d2e37 100644
--- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java
+++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java
@@ -788,7 +788,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
     w.addDocument(doc);
 
     IndexReader r = w.getReader();
-    assertTrue(q.rewrite(r) instanceof MatchNoDocsQuery);
+    assertTrue(q.rewrite(newSearcher(r)) instanceof MatchNoDocsQuery);
     IOUtils.close(w, r, dir);
   }
 
@@ -807,7 +807,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
     w.addDocument(doc);
 
     IndexReader r = w.getReader();
-    Query rewrite = q.rewrite(r);
+    Query rewrite = q.rewrite(newSearcher(r));
     assertTrue(rewrite instanceof TermQuery);
     assertEquals(new Term("field", "foo"), ((TermQuery) rewrite).getTerm());
     IOUtils.close(w, r, dir);
@@ -830,7 +830,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
     w.addDocument(doc);
 
     IndexReader r = w.getReader();
-    Query rewrite = q.rewrite(r);
+    Query rewrite = q.rewrite(newSearcher(r));
     assertTrue(rewrite instanceof PhraseQuery);
     Term[] terms = ((PhraseQuery) rewrite).getTerms();
     assertEquals(new Term("field", "foo"), terms[0]);
@@ -855,7 +855,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
+    public Query rewrite(IndexSearcher searcher) {
       return this;
     }
   }
@@ -876,7 +876,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
 
     IndexReader r = w.getReader();
     IndexSearcher searcher = newSearcher(r);
-    Query rewrittenQuery = q.rewrite(r);
+    Query rewrittenQuery = q.rewrite(searcher);
     assertTrue(rewrittenQuery instanceof TermAutomatonQuery);
 
     TopDocs topDocs = searcher.search(rewrittenQuery, 10);
@@ -918,7 +918,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
 
     IndexReader r = w.getReader();
     IndexSearcher searcher = newSearcher(r);
-    Query rewrittenQuery = q.rewrite(r);
+    Query rewrittenQuery = q.rewrite(searcher);
     assertTrue(
         "Rewritten query should be an instance of TermAutomatonQuery",
         rewrittenQuery instanceof TermAutomatonQuery);
@@ -953,7 +953,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
     w.addDocument(doc);
 
     IndexReader r = w.getReader();
-    Query rewrite = q.rewrite(r);
+    Query rewrite = q.rewrite(newSearcher(r));
     assertTrue(rewrite instanceof PhraseQuery);
     Term[] terms = ((PhraseQuery) rewrite).getTerms();
     assertEquals(new Term("field", "foo"), terms[0]);
@@ -982,7 +982,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
     w.addDocument(doc);
 
     IndexReader r = w.getReader();
-    Query rewrite = q.rewrite(r);
+    Query rewrite = q.rewrite(newSearcher(r));
     assertTrue(rewrite instanceof MultiPhraseQuery);
     Term[][] terms = ((MultiPhraseQuery) rewrite).getTermArrays();
     assertEquals(1, terms.length);
@@ -1017,7 +1017,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase {
     w.addDocument(doc);
 
     IndexReader r = w.getReader();
-    Query rewrite = q.rewrite(r);
+    Query rewrite = q.rewrite(newSearcher(r));
     assertTrue(rewrite instanceof MultiPhraseQuery);
     Term[][] terms = ((MultiPhraseQuery) rewrite).getTermArrays();
     assertEquals(2, terms.length);
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java
index 354a0196229..6483e425394 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java
@@ -17,7 +17,6 @@
 package org.apache.lucene.spatial.composite;
 
 import java.io.IOException;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.ConstantScoreScorer;
 import org.apache.lucene.search.ConstantScoreWeight;
@@ -47,12 +46,12 @@ public class CompositeVerifyQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query rewritten = indexQuery.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query rewritten = indexQuery.rewrite(indexSearcher);
     if (rewritten != indexQuery) {
       return new CompositeVerifyQuery(rewritten, predicateValueSource);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
index 77055d15ae2..0442b1c7ec0 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java
@@ -24,7 +24,6 @@ import org.apache.lucene.document.Field;
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.document.StoredField;
 import org.apache.lucene.index.DocValuesType;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
@@ -253,8 +252,8 @@ public class PointVectorStrategy extends SpatialStrategy {
     }
 
     @Override
-    public Query rewrite(IndexReader reader) throws IOException {
-      Query rewritten = inner.rewrite(reader);
+    public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+      Query rewritten = inner.rewrite(indexSearcher);
       if (rewritten == inner) return this;
       return new DistanceRangeQuery(rewritten, distanceSource, limit);
     }
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java
index 577c1a88656..8db16c194a7 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java
@@ -20,11 +20,11 @@ import static org.apache.lucene.analysis.miscellaneous.ConcatenateGraphFilter.SE
 import static org.apache.lucene.search.suggest.document.CompletionAnalyzer.HOLE_CHARACTER;
 
 import java.io.IOException;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.index.Terms;
+import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.suggest.BitsProducer;
 
@@ -83,11 +83,11 @@ public abstract class CompletionQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
     byte type = 0;
     boolean first = true;
     Terms terms;
-    for (LeafReaderContext context : reader.leaves()) {
+    for (LeafReaderContext context : indexSearcher.getLeafContexts()) {
       LeafReader leafReader = context.reader();
       try {
         if ((terms = leafReader.terms(getField())) == null) {
@@ -124,7 +124,7 @@ public abstract class CompletionQuery extends Query {
         }
       }
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java
index b4b97dbde29..e46e73bb1aa 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java
@@ -62,7 +62,7 @@ public class SuggestIndexSearcher extends IndexSearcher {
   public void suggest(CompletionQuery query, TopSuggestDocsCollector collector) throws IOException {
     // TODO use IndexSearcher.rewrite instead
     // have to implement equals() and hashCode() in CompletionQuerys and co
-    query = (CompletionQuery) query.rewrite(getIndexReader());
+    query = (CompletionQuery) query.rewrite(this);
     Weight weight = query.createWeight(this, collector.scoreMode(), 1f);
     for (LeafReaderContext context : getIndexReader().leaves()) {
       BulkScorer scorer = weight.bulkScorer(context);
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java b/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java
index 0947ff908bb..d4fcb653aba 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java
@@ -18,7 +18,6 @@ package org.apache.lucene.tests.search;
 
 import java.io.IOException;
 import java.util.Random;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryVisitor;
@@ -74,10 +73,10 @@ public final class AssertingQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query rewritten = in.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query rewritten = in.rewrite(indexSearcher);
     if (rewritten == in) {
-      return super.rewrite(reader);
+      return super.rewrite(indexSearcher);
     } else {
       return wrap(new Random(random.nextLong()), rewritten);
     }
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java b/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java
index ebb5c4bd132..5745aef757b 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java
@@ -19,7 +19,6 @@ package org.apache.lucene.tests.search;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.search.Explanation;
@@ -69,12 +68,12 @@ public final class BlockScoreQueryWrapper extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query rewritten = query.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query rewritten = query.rewrite(indexSearcher);
     if (rewritten != query) {
       return new BlockScoreQueryWrapper(rewritten, blockLength);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java b/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java
index 78dc60732fb..d58baae6936 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java
@@ -19,7 +19,6 @@ package org.apache.lucene.tests.search;
 import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
 import java.io.IOException;
 import java.util.Random;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.search.FilterWeight;
@@ -43,12 +42,12 @@ public class RandomApproximationQuery extends Query {
   }
 
   @Override
-  public Query rewrite(IndexReader reader) throws IOException {
-    final Query rewritten = query.rewrite(reader);
+  public Query rewrite(IndexSearcher indexSearcher) throws IOException {
+    final Query rewritten = query.rewrite(indexSearcher);
     if (rewritten != query) {
       return new RandomApproximationQuery(rewritten, random);
     }
-    return super.rewrite(reader);
+    return super.rewrite(indexSearcher);
   }
 
   @Override