You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jp...@apache.org on 2024/10/28 14:50:59 UTC

(lucene) branch main updated: Remove HitsThresholdChecker. (#13943)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 937432acd8d Remove HitsThresholdChecker. (#13943)
937432acd8d is described below

commit 937432acd8d0483604fc144bc97e423dd2df7156
Author: Adrien Grand <jp...@gmail.com>
AuthorDate: Mon Oct 28 15:50:53 2024 +0100

    Remove HitsThresholdChecker. (#13943)
    
    `TopScoreDocCollectorManager` has a dependency on `HitsThresholdChecker`, which
    is essentially a shared counter that is incremented until it reaches the total
    hits threshold, when the scorer can start dynamically pruning hits.
    
    A consequence of this removal is that dynamic pruning may start later, as soon
    as:
     - either the current slice collected `totalHitsThreshold` hits,
     - or another slice collected `totalHitsThreshold` hits and the current slice
       collected enough hits (up to 1,024) to check the shared
       `MaxScoreAccumulator`.
    
    So in short, it exchanges a bit more work globally in favor of a bit less
    contention. A longer-term goal of mine is to stop specializing our
    `CollectorManager`s based on whether they are going to be used concurrently or
    not.
---
 lucene/CHANGES.txt                                 |   2 +
 .../apache/lucene/search/HitsThresholdChecker.java | 147 ---------------------
 .../apache/lucene/search/TopFieldCollector.java    |  37 +++---
 .../lucene/search/TopFieldCollectorManager.java    |  11 +-
 .../apache/lucene/search/TopScoreDocCollector.java |  32 ++---
 .../lucene/search/TopScoreDocCollectorManager.java |  11 +-
 .../apache/lucene/search/TestTopDocsCollector.java |  14 +-
 .../lucene/search/TestTopFieldCollector.java       |  14 +-
 8 files changed, 52 insertions(+), 216 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 079707feae7..4e300574fa5 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -72,6 +72,8 @@ Optimizations
 
 * GITHUB#13899: Check ahead if we can get the count. (Lu Xugang)
 
+* GITHUB#13943: Removed shared `HitsThresholdChecker`, which reduces overhead
+  but may delay a bit when dynamic pruning kicks in. (Adrien Grand)
 
 Bug Fixes
 ---------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/HitsThresholdChecker.java b/lucene/core/src/java/org/apache/lucene/search/HitsThresholdChecker.java
deleted file mode 100644
index 78e1a589a77..00000000000
--- a/lucene/core/src/java/org/apache/lucene/search/HitsThresholdChecker.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.lucene.search;
-
-import java.util.concurrent.atomic.LongAdder;
-
-/** Used for defining custom algorithms to allow searches to early terminate */
-abstract class HitsThresholdChecker {
-  /** Implementation of HitsThresholdChecker which allows global hit counting */
-  private static class GlobalHitsThresholdChecker extends HitsThresholdChecker {
-    private final LongAdder globalHitCount = new LongAdder();
-    // Cache whether the threshold has been reached already. It is not volatile or synchronized on
-    // purpose to contain the overhead of reading the value similarly to what String#hashCode()
-    // does. This does not affect correctness.
-    private boolean thresholdReached = false;
-
-    GlobalHitsThresholdChecker(int totalHitsThreshold) {
-      super(totalHitsThreshold);
-      assert totalHitsThreshold != Integer.MAX_VALUE;
-    }
-
-    @Override
-    void incrementHitCount() {
-      if (thresholdReached == false) {
-        globalHitCount.increment();
-      }
-    }
-
-    @Override
-    boolean isThresholdReached() {
-      if (thresholdReached) {
-        return true;
-      }
-      if (globalHitCount.longValue() > getHitsThreshold()) {
-        thresholdReached = true;
-        return true;
-      }
-      return false;
-    }
-
-    @Override
-    ScoreMode scoreMode() {
-      return ScoreMode.TOP_SCORES;
-    }
-  }
-
-  /** Default implementation of HitsThresholdChecker to be used for single threaded execution */
-  private static class LocalHitsThresholdChecker extends HitsThresholdChecker {
-    private int hitCount;
-
-    LocalHitsThresholdChecker(int totalHitsThreshold) {
-      super(totalHitsThreshold);
-      assert totalHitsThreshold != Integer.MAX_VALUE;
-    }
-
-    @Override
-    void incrementHitCount() {
-      ++hitCount;
-    }
-
-    @Override
-    boolean isThresholdReached() {
-      return hitCount > getHitsThreshold();
-    }
-
-    @Override
-    ScoreMode scoreMode() {
-      return ScoreMode.TOP_SCORES;
-    }
-  }
-
-  /**
-   * No-op implementation of {@link HitsThresholdChecker} that does no counting, as the threshold
-   * can never be reached. This is useful for cases where early termination is never desired, so
-   * that the overhead of counting hits can be avoided.
-   */
-  private static final HitsThresholdChecker EXACT_HITS_COUNT_THRESHOLD_CHECKER =
-      new HitsThresholdChecker(Integer.MAX_VALUE) {
-        @Override
-        void incrementHitCount() {
-          // noop
-        }
-
-        @Override
-        boolean isThresholdReached() {
-          return false;
-        }
-
-        @Override
-        ScoreMode scoreMode() {
-          return ScoreMode.COMPLETE;
-        }
-      };
-
-  /*
-   * Returns a threshold checker that is useful for single threaded searches
-   */
-  static HitsThresholdChecker create(final int totalHitsThreshold) {
-    return totalHitsThreshold == Integer.MAX_VALUE
-        ? HitsThresholdChecker.EXACT_HITS_COUNT_THRESHOLD_CHECKER
-        : new LocalHitsThresholdChecker(totalHitsThreshold);
-  }
-
-  /*
-   * Returns a threshold checker that is based on a shared counter
-   */
-  static HitsThresholdChecker createShared(final int totalHitsThreshold) {
-    return totalHitsThreshold == Integer.MAX_VALUE
-        ? HitsThresholdChecker.EXACT_HITS_COUNT_THRESHOLD_CHECKER
-        : new GlobalHitsThresholdChecker(totalHitsThreshold);
-  }
-
-  private final int totalHitsThreshold;
-
-  HitsThresholdChecker(int totalHitsThreshold) {
-    if (totalHitsThreshold < 0) {
-      throw new IllegalArgumentException(
-          "totalHitsThreshold must be >= 0, got " + totalHitsThreshold);
-    }
-    this.totalHitsThreshold = totalHitsThreshold;
-  }
-
-  final int getHitsThreshold() {
-    return totalHitsThreshold;
-  }
-
-  abstract boolean isThresholdReached();
-
-  abstract ScoreMode scoreMode();
-
-  abstract void incrementHitCount();
-}
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
index eac31bf89d0..384f5fa1168 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
@@ -71,15 +71,14 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
     }
 
     void countHit(int doc) throws IOException {
-      ++totalHits;
-      hitsThresholdChecker.incrementHitCount();
+      int hitCountSoFar = ++totalHits;
 
-      if (minScoreAcc != null && (totalHits & minScoreAcc.modInterval) == 0) {
+      if (minScoreAcc != null && (hitCountSoFar & minScoreAcc.modInterval) == 0) {
         updateGlobalMinCompetitiveScore(scorer);
       }
       if (scoreMode.isExhaustive() == false
           && totalHitsRelation == TotalHits.Relation.EQUAL_TO
-          && hitsThresholdChecker.isThresholdReached()) {
+          && totalHits > totalHitsThreshold) {
         // for the first time hitsThreshold is reached, notify comparator about this
         comparator.setHitsThresholdReached();
         totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO;
@@ -92,7 +91,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
         // this document is larger than anything else in the queue, and
         // therefore not competitive.
         if (searchSortPartOfIndexSort) {
-          if (hitsThresholdChecker.isThresholdReached()) {
+          if (totalHits > totalHitsThreshold) {
             totalHitsRelation = Relation.GREATER_THAN_OR_EQUAL_TO;
             throw new CollectionTerminatedException();
           } else {
@@ -180,9 +179,9 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
         Sort sort,
         FieldValueHitQueue<Entry> queue,
         int numHits,
-        HitsThresholdChecker hitsThresholdChecker,
+        int totalHitsThreshold,
         MaxScoreAccumulator minScoreAcc) {
-      super(queue, numHits, hitsThresholdChecker, sort.needsScores(), minScoreAcc);
+      super(queue, numHits, totalHitsThreshold, sort.needsScores(), minScoreAcc);
       this.sort = sort;
       this.queue = queue;
     }
@@ -235,9 +234,9 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
         FieldValueHitQueue<Entry> queue,
         FieldDoc after,
         int numHits,
-        HitsThresholdChecker hitsThresholdChecker,
+        int totalHitsThreshold,
         MaxScoreAccumulator minScoreAcc) {
-      super(queue, numHits, hitsThresholdChecker, sort.needsScores(), minScoreAcc);
+      super(queue, numHits, totalHitsThreshold, sort.needsScores(), minScoreAcc);
       this.sort = sort;
       this.queue = queue;
       this.after = after;
@@ -301,7 +300,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
   private static final ScoreDoc[] EMPTY_SCOREDOCS = new ScoreDoc[0];
 
   final int numHits;
-  final HitsThresholdChecker hitsThresholdChecker;
+  final int totalHitsThreshold;
   final FieldComparator<?> firstComparator;
   final boolean canSetMinScore;
 
@@ -327,25 +326,25 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
   private TopFieldCollector(
       FieldValueHitQueue<Entry> pq,
       int numHits,
-      HitsThresholdChecker hitsThresholdChecker,
+      int totalHitsThreshold,
       boolean needsScores,
       MaxScoreAccumulator minScoreAcc) {
     super(pq);
     this.needsScores = needsScores;
     this.numHits = numHits;
-    this.hitsThresholdChecker = hitsThresholdChecker;
+    this.totalHitsThreshold = Math.max(totalHitsThreshold, numHits);
     this.numComparators = pq.getComparators().length;
     this.firstComparator = pq.getComparators()[0];
     int reverseMul = pq.reverseMul[0];
 
     if (firstComparator.getClass().equals(FieldComparator.RelevanceComparator.class)
         && reverseMul == 1 // if the natural sort is preserved (sort by descending relevance)
-        && hitsThresholdChecker.getHitsThreshold() != Integer.MAX_VALUE) {
+        && totalHitsThreshold != Integer.MAX_VALUE) {
       scoreMode = ScoreMode.TOP_SCORES;
       canSetMinScore = true;
     } else {
       canSetMinScore = false;
-      if (hitsThresholdChecker.getHitsThreshold() != Integer.MAX_VALUE) {
+      if (totalHitsThreshold != Integer.MAX_VALUE) {
         scoreMode = needsScores ? ScoreMode.TOP_DOCS_WITH_SCORES : ScoreMode.TOP_DOCS;
       } else {
         scoreMode = needsScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES;
@@ -361,10 +360,10 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
 
   protected void updateGlobalMinCompetitiveScore(Scorable scorer) throws IOException {
     assert minScoreAcc != null;
-    if (canSetMinScore && hitsThresholdChecker.isThresholdReached()) {
-      // we can start checking the global maximum score even
-      // if the local queue is not full because the threshold
-      // is reached.
+    if (canSetMinScore) {
+      // we can start checking the global maximum score even if the local queue is not full or if
+      // the threshold is not reached on the local competitor: the fact that there is a shared min
+      // competitive score implies that one of the collectors hit its totalHitsThreshold already
       long maxMinScore = minScoreAcc.getRaw();
       float score;
       if (maxMinScore != Long.MIN_VALUE
@@ -377,7 +376,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
   }
 
   protected void updateMinCompetitiveScore(Scorable scorer) throws IOException {
-    if (canSetMinScore && queueFull && hitsThresholdChecker.isThresholdReached()) {
+    if (canSetMinScore && queueFull && totalHits > totalHitsThreshold) {
       assert bottom != null;
       float minScore = (float) firstComparator.value(bottom.slot);
       if (minScore > minCompetitiveScore) {
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollectorManager.java b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollectorManager.java
index 2d4a0c0e215..48c1ca98091 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollectorManager.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollectorManager.java
@@ -32,7 +32,7 @@ public class TopFieldCollectorManager implements CollectorManager<TopFieldCollec
   private final Sort sort;
   private final int numHits;
   private final FieldDoc after;
-  private final HitsThresholdChecker hitsThresholdChecker;
+  private final int totalHitsThreshold;
   private final MaxScoreAccumulator minScoreAcc;
   private final List<TopFieldCollector> collectors;
   private final boolean supportsConcurrency;
@@ -89,10 +89,7 @@ public class TopFieldCollectorManager implements CollectorManager<TopFieldCollec
     this.numHits = numHits;
     this.after = after;
     this.supportsConcurrency = supportsConcurrency;
-    this.hitsThresholdChecker =
-        supportsConcurrency
-            ? HitsThresholdChecker.createShared(Math.max(totalHitsThreshold, numHits))
-            : HitsThresholdChecker.create(Math.max(totalHitsThreshold, numHits));
+    this.totalHitsThreshold = totalHitsThreshold;
     this.minScoreAcc =
         supportsConcurrency && totalHitsThreshold != Integer.MAX_VALUE
             ? new MaxScoreAccumulator()
@@ -162,7 +159,7 @@ public class TopFieldCollectorManager implements CollectorManager<TopFieldCollec
       }
       collector =
           new TopFieldCollector.SimpleFieldCollector(
-              sort, queue, numHits, hitsThresholdChecker, minScoreAcc);
+              sort, queue, numHits, totalHitsThreshold, minScoreAcc);
     } else {
       if (after.fields == null) {
         throw new IllegalArgumentException(
@@ -178,7 +175,7 @@ public class TopFieldCollectorManager implements CollectorManager<TopFieldCollec
       }
       collector =
           new TopFieldCollector.PagingFieldCollector(
-              sort, queue, after, numHits, hitsThresholdChecker, minScoreAcc);
+              sort, queue, after, numHits, totalHitsThreshold, minScoreAcc);
     }
 
     collectors.add(collector);
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java
index 025e7937601..4e299cbb618 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java
@@ -45,8 +45,8 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
   static class SimpleTopScoreDocCollector extends TopScoreDocCollector {
 
     SimpleTopScoreDocCollector(
-        int numHits, HitsThresholdChecker hitsThresholdChecker, MaxScoreAccumulator minScoreAcc) {
-      super(numHits, hitsThresholdChecker, minScoreAcc);
+        int numHits, int totalHitsThreshold, MaxScoreAccumulator minScoreAcc) {
+      super(numHits, totalHitsThreshold, minScoreAcc);
     }
 
     @Override
@@ -71,7 +71,6 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
           float score = scorer.score();
 
           int hitCountSoFar = ++totalHits;
-          hitsThresholdChecker.incrementHitCount();
 
           if (minScoreAcc != null && (hitCountSoFar & minScoreAcc.modInterval) == 0) {
             updateGlobalMinCompetitiveScore(scorer);
@@ -80,7 +79,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
           if (score <= pqTop.score) {
             // Note: for queries that match lots of hits, this is the common case: most hits are not
             // competitive.
-            if (totalHitsRelation == TotalHits.Relation.EQUAL_TO) {
+            if (hitCountSoFar == totalHitsThreshold + 1) {
               // we just reached totalHitsThreshold, we can start setting the min
               // competitive score now
               updateMinCompetitiveScore(scorer);
@@ -108,11 +107,8 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
     private final ScoreDoc after;
 
     PagingTopScoreDocCollector(
-        int numHits,
-        ScoreDoc after,
-        HitsThresholdChecker hitsThresholdChecker,
-        MaxScoreAccumulator minScoreAcc) {
-      super(numHits, hitsThresholdChecker, minScoreAcc);
+        int numHits, ScoreDoc after, int totalHitsThreshold, MaxScoreAccumulator minScoreAcc) {
+      super(numHits, totalHitsThreshold, minScoreAcc);
       this.after = after;
     }
 
@@ -158,7 +154,6 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
           float score = scorer.score();
 
           int hitCountSoFar = ++totalHits;
-          hitsThresholdChecker.incrementHitCount();
 
           if (minScoreAcc != null && (hitCountSoFar & minScoreAcc.modInterval) == 0) {
             updateGlobalMinCompetitiveScore(scorer);
@@ -178,8 +173,8 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
           if (score <= pqTop.score) {
             // Note: for queries that match lots of hits, this is the common case: most hits are not
             // competitive.
-            if (totalHitsRelation == TotalHits.Relation.EQUAL_TO) {
-              // we just reached totalHitsThreshold, we can start setting the min
+            if (hitCountSoFar == totalHitsThreshold + 1) {
+              // we just exceeded totalHitsThreshold, we can start setting the min
               // competitive score now
               updateMinCompetitiveScore(scorer);
             }
@@ -204,20 +199,18 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
 
   int docBase;
   ScoreDoc pqTop;
-  final HitsThresholdChecker hitsThresholdChecker;
+  final int totalHitsThreshold;
   final MaxScoreAccumulator minScoreAcc;
   float minCompetitiveScore;
 
   // prevents instantiation
-  TopScoreDocCollector(
-      int numHits, HitsThresholdChecker hitsThresholdChecker, MaxScoreAccumulator minScoreAcc) {
+  TopScoreDocCollector(int numHits, int totalHitsThreshold, MaxScoreAccumulator minScoreAcc) {
     super(new HitQueue(numHits, true));
-    assert hitsThresholdChecker != null;
 
     // HitQueue implements getSentinelObject to return a ScoreDoc, so we know
     // that at this point top() is already initialized.
     pqTop = pq.top();
-    this.hitsThresholdChecker = hitsThresholdChecker;
+    this.totalHitsThreshold = totalHitsThreshold;
     this.minScoreAcc = minScoreAcc;
   }
 
@@ -232,7 +225,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
 
   @Override
   public ScoreMode scoreMode() {
-    return hitsThresholdChecker.scoreMode();
+    return totalHitsThreshold == Integer.MAX_VALUE ? ScoreMode.COMPLETE : ScoreMode.TOP_SCORES;
   }
 
   protected void updateGlobalMinCompetitiveScore(Scorable scorer) throws IOException {
@@ -245,7 +238,6 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
       float score = MaxScoreAccumulator.toScore(maxMinScore);
       score = docBase >= MaxScoreAccumulator.docId(maxMinScore) ? Math.nextUp(score) : score;
       if (score > minCompetitiveScore) {
-        assert hitsThresholdChecker.isThresholdReached();
         scorer.setMinCompetitiveScore(score);
         minCompetitiveScore = score;
         totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO;
@@ -254,7 +246,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
   }
 
   protected void updateMinCompetitiveScore(Scorable scorer) throws IOException {
-    if (hitsThresholdChecker.isThresholdReached()) {
+    if (totalHits > totalHitsThreshold) {
       // since we tie-break on doc id and collect in doc id order, we can require
       // the next float
       // pqTop is never null since TopScoreDocCollector fills the priority queue with sentinel
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollectorManager.java b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollectorManager.java
index 94a4e1a82d3..7933313febe 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollectorManager.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollectorManager.java
@@ -29,7 +29,7 @@ public class TopScoreDocCollectorManager
     implements CollectorManager<TopScoreDocCollector, TopDocs> {
   private final int numHits;
   private final ScoreDoc after;
-  private final HitsThresholdChecker hitsThresholdChecker;
+  private final int totalHitsThreshold;
   private final MaxScoreAccumulator minScoreAcc;
   private final boolean supportsConcurrency;
   private boolean collectorCreated;
@@ -71,10 +71,7 @@ public class TopScoreDocCollectorManager
     this.numHits = numHits;
     this.after = after;
     this.supportsConcurrency = supportsConcurrency;
-    this.hitsThresholdChecker =
-        supportsConcurrency
-            ? HitsThresholdChecker.createShared(Math.max(totalHitsThreshold, numHits))
-            : HitsThresholdChecker.create(Math.max(totalHitsThreshold, numHits));
+    this.totalHitsThreshold = Math.max(totalHitsThreshold, numHits);
     this.minScoreAcc =
         supportsConcurrency && totalHitsThreshold != Integer.MAX_VALUE
             ? new MaxScoreAccumulator()
@@ -141,10 +138,10 @@ public class TopScoreDocCollectorManager
 
     if (after == null) {
       return new TopScoreDocCollector.SimpleTopScoreDocCollector(
-          numHits, hitsThresholdChecker, minScoreAcc);
+          numHits, totalHitsThreshold, minScoreAcc);
     } else {
       return new TopScoreDocCollector.PagingTopScoreDocCollector(
-          numHits, after, hitsThresholdChecker, minScoreAcc);
+          numHits, after, totalHitsThreshold, minScoreAcc);
     }
   }
 
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java
index 14b51ca214e..44bd66148cd 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java
@@ -529,26 +529,24 @@ public class TestTopDocsCollector extends LuceneTestCase {
 
     scorer.score = 2;
     leafCollector.collect(1);
-    assertEquals(2f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
-    assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
-    assertNull(scorer2.minCompetitiveScore);
+    assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
+    assertNull(scorer.minCompetitiveScore);
 
     scorer2.score = 9;
     leafCollector2.collect(1);
-    assertEquals(6f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
-    assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
-    assertEquals(Math.nextUp(6f), scorer2.minCompetitiveScore, 0f);
+    assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
+    assertNull(scorer2.minCompetitiveScore);
 
     scorer2.score = 7;
     leafCollector2.collect(2);
     assertEquals(MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 7f, 0f);
-    assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
+    assertNull(scorer.minCompetitiveScore);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
 
     scorer2.score = 1;
     leafCollector2.collect(3);
     assertEquals(MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 7f, 0f);
-    assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
+    assertNull(scorer.minCompetitiveScore);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
 
     scorer.score = 10;
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
index c507eb0f647..bd0d408e0b2 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
@@ -587,26 +587,24 @@ public class TestTopFieldCollector extends LuceneTestCase {
 
     scorer.score = 2;
     leafCollector.collect(1);
-    assertEquals(2f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
-    assertEquals(2f, scorer.minCompetitiveScore, 0f);
-    assertNull(scorer2.minCompetitiveScore);
+    assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
+    assertNull(scorer.minCompetitiveScore);
 
     scorer2.score = 9;
     leafCollector2.collect(1);
-    assertEquals(6f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
-    assertEquals(2f, scorer.minCompetitiveScore, 0f);
-    assertEquals(6f, scorer2.minCompetitiveScore, 0f);
+    assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
+    assertNull(scorer2.minCompetitiveScore);
 
     scorer2.score = 7;
     leafCollector2.collect(2);
     assertEquals(7f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
-    assertEquals(2f, scorer.minCompetitiveScore, 0f);
+    assertNull(scorer.minCompetitiveScore);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
 
     scorer2.score = 1;
     leafCollector2.collect(3);
     assertEquals(7f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
-    assertEquals(2f, scorer.minCompetitiveScore, 0f);
+    assertNull(scorer.minCompetitiveScore);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
 
     scorer.score = 10;