Skip to content

Commit 4480cf0

Browse files
authored
Enable BMW for single-scorer boolean queries by removing early return in scorer_union (#2915)
The early return for `scorers.len() == 1` in `scorer_union` short-circuits a single TermScorer into `SpecializedScorer::Other`, bypassing the `TermUnion` path that enables block-max WAND (BMW) in `for_each_pruning`. This was originally addressed in PR #2898 (backed out), which added a special case in `BooleanWeight::for_each_pruning`. PR #2912 (merged as d27ca16) added a single-scorer fast path inside `block_wand` itself, but did not remove this early return — so a single SHOULD TermScorer still never reaches the BMW path. Removing the early return lets a single TermScorer with freq reading flow through to `SpecializedScorer::TermUnion`, where `block_wand` → `block_wand_single_scorer` handles it efficiently.
1 parent d47abdf commit 4480cf0

1 file changed

Lines changed: 6 additions & 4 deletions

File tree

src/query/boolean_query/boolean_weight.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use crate::query::score_combiner::{DoNothingCombiner, ScoreCombiner};
99
use crate::query::term_query::TermScorer;
1010
use crate::query::weight::{for_each_docset_buffered, for_each_pruning_scorer, for_each_scorer};
1111
use crate::query::{
12-
intersect_scorers, AllScorer, BufferedUnionScorer, EmptyScorer, Exclude, Explanation,
13-
Intersection, Occur, RequiredOptionalScorer, Scorer, Weight,
12+
intersect_scorers, AllScorer, BufferedUnionScorer, EmptyScorer, Exclude, Explanation, Occur,
13+
RequiredOptionalScorer, Scorer, Weight,
1414
};
1515
use crate::{DocId, Score};
1616

@@ -50,10 +50,9 @@ where
5050
TScoreCombiner: ScoreCombiner,
5151
{
5252
assert!(!scorers.is_empty());
53-
if scorers.len() == 1 {
53+
if scorers.len() == 1 && !scorers[0].is::<TermScorer>() {
5454
return SpecializedScorer::Other(scorers.into_iter().next().unwrap()); //< we checked the size beforehand
5555
}
56-
5756
{
5857
let is_all_term_queries = scorers.iter().all(|scorer| scorer.is::<TermScorer>());
5958
if is_all_term_queries {
@@ -67,6 +66,9 @@ where
6766
{
6867
// Block wand is only available if we read frequencies.
6968
return SpecializedScorer::TermUnion(scorers);
69+
} else if scorers.len() == 1 {
70+
// Single TermScorer without freq reading — unwrap directly.
71+
return SpecializedScorer::Other(Box::new(scorers.into_iter().next().unwrap()));
7072
} else {
7173
return SpecializedScorer::Other(Box::new(BufferedUnionScorer::build(
7274
scorers,

0 commit comments

Comments
 (0)