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 2025/06/03 05:30:19 UTC
(lucene) 01/05: Keep evaluating conjunction one doc-at-a-time until dynamic pruning kicks in. (#14739)
This is an automated email from the ASF dual-hosted git repository.
jpountz pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/lucene.git
commit 92de7a200751132e3470284c78793ce2f9aa477c
Author: Adrien Grand <jp...@gmail.com>
AuthorDate: Mon Jun 2 17:03:05 2025 +0200
Keep evaluating conjunction one doc-at-a-time until dynamic pruning kicks in. (#14739)
This essentially reverts the change from #14701 for conjunctive queries that
have not reached their `totalHitsThreshold` yet. This should speed up queries
whose total number of matches is in the order of `totalHitsThreshold` or less,
such as filtered conjunctions on nightly benchmarks.
---
.../search/BlockMaxConjunctionBulkScorer.java | 66 ++++++++++++++++++----
1 file changed, 55 insertions(+), 11 deletions(-)
diff --git a/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionBulkScorer.java b/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionBulkScorer.java
index 7091777a262..e2e063feb5e 100644
--- a/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionBulkScorer.java
+++ b/lucene/core/src/java/org/apache/lucene/search/BlockMaxConjunctionBulkScorer.java
@@ -87,18 +87,64 @@ final class BlockMaxConjunctionBulkScorer extends BulkScorer {
// NOTE: windowMax is inclusive
int windowMax = Math.min(scorers[0].advanceShallow(windowMin), max - 1);
- float maxWindowScore = Float.POSITIVE_INFINITY;
if (0 < scorable.minCompetitiveScore) {
- maxWindowScore = computeMaxScore(windowMin, windowMax);
+ float maxWindowScore = computeMaxScore(windowMin, windowMax);
+ scoreWindowScoreFirst(collector, acceptDocs, windowMin, windowMax + 1, maxWindowScore);
+ } else {
+ scoreWindowDocFirst(collector, acceptDocs, windowMin, windowMax + 1);
}
- scoreWindow(collector, acceptDocs, windowMin, windowMax + 1, maxWindowScore);
windowMin = Math.max(lead.docID(), windowMax + 1);
}
return windowMin >= maxDoc ? DocIdSetIterator.NO_MORE_DOCS : windowMin;
}
- private void scoreWindow(
+ /**
+ * Score a window of doc IDs by first finding agreement between all iterators, and only then
+ * compute scores and call the collector.
+ */
+ private void scoreWindowDocFirst(LeafCollector collector, Bits acceptDocs, int min, int max)
+ throws IOException {
+ int doc = lead.docID();
+ if (doc < min) {
+ doc = lead.advance(min);
+ }
+
+ outer:
+ while (doc < max) {
+ if (acceptDocs == null || acceptDocs.get(doc)) {
+ for (int i = 1; i < iterators.length; ++i) {
+ DocIdSetIterator iterator = iterators[i];
+ int otherDoc = iterator.docID();
+ if (otherDoc < doc) {
+ otherDoc = iterator.advance(doc);
+ }
+ if (doc != otherDoc) {
+ doc = lead.advance(otherDoc);
+ continue outer;
+ }
+ }
+
+ double score = 0;
+ for (Scorable scorable : scorables) {
+ score += scorable.score();
+ }
+ scorable.score = (float) score;
+ collector.collect(doc);
+ }
+ doc = lead.nextDoc();
+ }
+ }
+
+ /**
+ * Score a window of doc IDs by computing matches and scores on the lead costly clause, then
+ * iterate other clauses one by one to remove documents that do not match and increase the global
+ * score by the score of the current clause. This is often faster when a minimum competitive score
+ * is set, as score computations can be more efficient (e.g. thanks to vectorization) and because
+ * we can skip advancing other clauses if the global score so far is not high enough for a doc to
+ * have a chance of being competitive.
+ */
+ private void scoreWindowScoreFirst(
LeafCollector collector, Bits acceptDocs, int min, int max, float maxWindowScore)
throws IOException {
if (maxWindowScore < scorable.minCompetitiveScore) {
@@ -120,13 +166,11 @@ final class BlockMaxConjunctionBulkScorer extends BulkScorer {
docAndScoreAccBuffer.copyFrom(docAndScoreBuffer);
for (int i = 1; i < scorers.length; ++i) {
- if (scorable.minCompetitiveScore > 0) {
- ScorerUtil.filterCompetitiveHits(
- docAndScoreAccBuffer,
- sumOfOtherClauses[i],
- scorable.minCompetitiveScore,
- scorers.length);
- }
+ ScorerUtil.filterCompetitiveHits(
+ docAndScoreAccBuffer,
+ sumOfOtherClauses[i],
+ scorable.minCompetitiveScore,
+ scorers.length);
ScorerUtil.applyRequiredClause(docAndScoreAccBuffer, iterators[i], scorables[i]);
}