Better handle dynamic pruning when the leading clause has a single impact block. (#13904)

`BlockMaxConjunctionBulkScorer` only checks if it can early exit based on
impacts once per window, and windows are computed using impact blocks of the
leading clause. So this logic is defeated if the leading clause produces a
single block (e.g. `ConstantScoreQuery`). This commit addresses this problem by
artificially lowering the window size to contain ~128 docs of the leading
clause.
This commit is contained in:
Adrien Grand 2024-10-15 16:17:20 +02:00
parent 5727b8ce59
commit 92c4f51224
2 changed files with 18 additions and 3 deletions

View File

@ -27,6 +27,10 @@ Optimizations
* GITHUB#13800: MaxScoreBulkScorer now recomputes scorer partitions when the
minimum competitive allows for a more favorable partitioning. (Adrien Grand)
* GITHUB#13904: BlockMaxConjunctionBulkScorer can now early exit when the
leading clause has a single impact block (e.g. ConstantScoreQuery).
(Adrien Grand)
Bug Fixes
---------------------
* GITHUB#13832: Fixed an issue where the DefaultPassageFormatter.format method did not format passages as intended

View File

@ -85,9 +85,20 @@ final class BlockMaxConjunctionBulkScorer extends BulkScorer {
int windowMin = Math.max(lead1.docID(), min);
while (windowMin < max) {
// Use impacts of the least costly scorer to compute windows
// NOTE: windowMax is inclusive
int windowMax = Math.min(scorers[0].advanceShallow(windowMin), max - 1);
// Use impacts of the least costly scorer to compute windows to keep the per-block overhead
// under control.
// NOTE: windowMax is inclusive.
int windowMax = scorer1.advanceShallow(windowMin);
if (windowMax == DocIdSetIterator.NO_MORE_DOCS) {
// If the query doesn't have impacts anymore, or has a single block for the whole doc ID
// space (e.g. ConstantScoreQuery), then we try to create a block that has ~128 docs of the
// leading clause. This gives us higher chances to exit early based on the maximum scores of
// other clauses.
long windowSize = 128L * maxDoc / Math.max(1, lead1.cost());
windowSize = Math.max(windowSize, 128L);
windowMax = (int) Math.min(Integer.MAX_VALUE, windowMin + windowSize);
}
windowMax = Math.min(windowMax, max - 1);
float maxWindowScore = Float.POSITIVE_INFINITY;
if (0 < scorable.minCompetitiveScore) {