@@ -9,7 +9,7 @@ use crate::query::score_combiner::{DoNothingCombiner, ScoreCombiner};
99use crate :: query:: term_query:: TermScorer ;
1010use crate :: query:: weight:: { for_each_docset_buffered, for_each_pruning_scorer, for_each_scorer} ;
1111use crate :: query:: {
12- intersect_scorers, BufferedUnionScorer , EmptyScorer , Exclude , Explanation , Occur ,
12+ intersect_scorers, AllScorer , BufferedUnionScorer , EmptyScorer , Exclude , Explanation , Occur ,
1313 RequiredOptionalScorer , Scorer , Weight ,
1414} ;
1515use crate :: { DocId , Score } ;
@@ -97,6 +97,15 @@ fn into_box_scorer<TScoreCombiner: ScoreCombiner>(
9797 }
9898}
9999
100+ enum ShouldScorersCombinationMethod {
101+ // Should scorers are irrelevant.
102+ Ignored ,
103+ // Only contributes to final score.
104+ Optional ( SpecializedScorer ) ,
105+ // Regardless of score, the should scorers may impact whether a document is matching or not.
106+ Required ( SpecializedScorer ) ,
107+ }
108+
100109/// Weight associated to the `BoolQuery`.
101110pub struct BooleanWeight < TScoreCombiner : ScoreCombiner > {
102111 weights : Vec < ( Occur , Box < dyn Weight > ) > ,
@@ -159,104 +168,171 @@ impl<TScoreCombiner: ScoreCombiner> BooleanWeight<TScoreCombiner> {
159168 ) -> crate :: Result < SpecializedScorer > {
160169 let num_docs = reader. num_docs ( ) ;
161170 let mut per_occur_scorers = self . per_occur_scorers ( reader, boost) ?;
162- // Indicate how should clauses are combined with other clauses.
163- enum CombinationMethod {
164- Ignored ,
165- // Only contributes to final score.
166- Optional ( SpecializedScorer ) ,
167- Required ( SpecializedScorer ) ,
171+
172+ // Indicate how should clauses are combined with must clauses.
173+ let mut must_scorers: Vec < Box < dyn Scorer > > =
174+ per_occur_scorers. remove ( & Occur :: Must ) . unwrap_or_default ( ) ;
175+ let must_special_scorer_counts = remove_and_count_all_and_empty_scorers ( & mut must_scorers) ;
176+
177+ if must_special_scorer_counts. num_empty_scorers > 0 {
178+ return Ok ( SpecializedScorer :: Other ( Box :: new ( EmptyScorer ) ) ) ;
179+ }
180+
181+ let mut should_scorers = per_occur_scorers. remove ( & Occur :: Should ) . unwrap_or_default ( ) ;
182+ let should_special_scorer_counts =
183+ remove_and_count_all_and_empty_scorers ( & mut should_scorers) ;
184+
185+ let mut exclude_scorers: Vec < Box < dyn Scorer > > = per_occur_scorers
186+ . remove ( & Occur :: MustNot )
187+ . unwrap_or_default ( ) ;
188+ let exclude_special_scorer_counts =
189+ remove_and_count_all_and_empty_scorers ( & mut exclude_scorers) ;
190+
191+ if exclude_special_scorer_counts. num_all_scorers > 0 {
192+ // We exclude all documents at one point.
193+ return Ok ( SpecializedScorer :: Other ( Box :: new ( EmptyScorer ) ) ) ;
168194 }
169- let mut must_scorers = per_occur_scorers. remove ( & Occur :: Must ) ;
170- let should_opt = if let Some ( mut should_scorers) = per_occur_scorers. remove ( & Occur :: Should )
171- {
195+
196+ let minimum_number_should_match = self
197+ . minimum_number_should_match
198+ . saturating_sub ( should_special_scorer_counts. num_all_scorers ) ;
199+
200+ let should_scorers: ShouldScorersCombinationMethod = {
172201 let num_of_should_scorers = should_scorers. len ( ) ;
173- if self . minimum_number_should_match > num_of_should_scorers {
202+ if minimum_number_should_match > num_of_should_scorers {
203+ // We don't have enough scorers to satisfy the minimum number of should matches.
204+ // The request will match no documents.
174205 return Ok ( SpecializedScorer :: Other ( Box :: new ( EmptyScorer ) ) ) ;
175206 }
176- match self . minimum_number_should_match {
177- 0 => CombinationMethod :: Optional ( scorer_union (
207+ match minimum_number_should_match {
208+ 0 if num_of_should_scorers == 0 => ShouldScorersCombinationMethod :: Ignored ,
209+ 0 => ShouldScorersCombinationMethod :: Optional ( scorer_union (
178210 should_scorers,
179211 & score_combiner_fn,
180212 num_docs,
181213 ) ) ,
182- 1 => CombinationMethod :: Required ( scorer_union (
214+ 1 => ShouldScorersCombinationMethod :: Required ( scorer_union (
183215 should_scorers,
184216 & score_combiner_fn,
185217 num_docs,
186218 ) ) ,
187219 n if num_of_should_scorers == n => {
188220 // When num_of_should_scorers equals the number of should clauses,
189221 // they are no different from must clauses.
190- must_scorers = match must_scorers. take ( ) {
191- Some ( mut must_scorers) => {
192- must_scorers. append ( & mut should_scorers) ;
193- Some ( must_scorers)
194- }
195- None => Some ( should_scorers) ,
196- } ;
197- CombinationMethod :: Ignored
222+ must_scorers. append ( & mut should_scorers) ;
223+ ShouldScorersCombinationMethod :: Ignored
198224 }
199- _ => CombinationMethod :: Required ( SpecializedScorer :: Other ( scorer_disjunction (
200- should_scorers,
201- score_combiner_fn ( ) ,
202- self . minimum_number_should_match ,
203- ) ) ) ,
225+ _ => ShouldScorersCombinationMethod :: Required ( SpecializedScorer :: Other (
226+ scorer_disjunction (
227+ should_scorers,
228+ score_combiner_fn ( ) ,
229+ self . minimum_number_should_match ,
230+ ) ,
231+ ) ) ,
204232 }
233+ } ;
234+
235+ let exclude_scorer_opt: Option < Box < dyn Scorer > > = if exclude_scorers. is_empty ( ) {
236+ None
205237 } else {
206- // None of should clauses are provided.
207- if self . minimum_number_should_match > 0 {
208- return Ok ( SpecializedScorer :: Other ( Box :: new ( EmptyScorer ) ) ) ;
209- } else {
210- CombinationMethod :: Ignored
211- }
238+ let exclude_specialized_scorer: SpecializedScorer =
239+ scorer_union ( exclude_scorers, DoNothingCombiner :: default, num_docs) ;
240+ Some ( into_box_scorer (
241+ exclude_specialized_scorer,
242+ DoNothingCombiner :: default,
243+ num_docs,
244+ ) )
212245 } ;
213- let exclude_scorer_opt: Option < Box < dyn Scorer > > = per_occur_scorers
214- . remove ( & Occur :: MustNot )
215- . map ( |scorers| scorer_union ( scorers, DoNothingCombiner :: default, num_docs) )
216- . map ( |specialized_scorer : SpecializedScorer | {
217- into_box_scorer ( specialized_scorer, DoNothingCombiner :: default, num_docs)
218- } ) ;
219- let positive_scorer = match ( should_opt, must_scorers) {
220- ( CombinationMethod :: Ignored , Some ( must_scorers) ) => {
221- SpecializedScorer :: Other ( intersect_scorers ( must_scorers, num_docs) )
246+
247+ let include_scorer = match ( should_scorers, must_scorers) {
248+ ( ShouldScorersCombinationMethod :: Ignored , must_scorers) => {
249+ let boxed_scorer: Box < dyn Scorer > = if must_scorers. is_empty ( ) {
250+ // We do not have any should scorers, nor all scorers.
251+ // There are still two cases here.
252+ //
253+ // If this follows the removal of some AllScorers in the should/must clauses,
254+ // then we match all documents.
255+ //
256+ // Otherwise, it is really just an EmptyScorer.
257+ if must_special_scorer_counts. num_all_scorers
258+ + should_special_scorer_counts. num_all_scorers
259+ > 0
260+ {
261+ Box :: new ( AllScorer :: new ( reader. max_doc ( ) ) )
262+ } else {
263+ Box :: new ( EmptyScorer )
264+ }
265+ } else {
266+ intersect_scorers ( must_scorers, num_docs)
267+ } ;
268+ SpecializedScorer :: Other ( boxed_scorer)
222269 }
223- ( CombinationMethod :: Optional ( should_scorer) , Some ( must_scorers) ) => {
224- let must_scorer = intersect_scorers ( must_scorers, num_docs) ;
225- if self . scoring_enabled {
226- SpecializedScorer :: Other ( Box :: new (
227- RequiredOptionalScorer :: < _ , _ , TScoreCombiner > :: new (
270+ ( ShouldScorersCombinationMethod :: Optional ( should_scorer) , must_scorers) => {
271+ if must_scorers. is_empty ( ) && must_special_scorer_counts. num_all_scorers == 0 {
272+ // Optional options are promoted to required if no must scorers exists.
273+ should_scorer
274+ } else {
275+ let must_scorer = intersect_scorers ( must_scorers, num_docs) ;
276+ if self . scoring_enabled {
277+ SpecializedScorer :: Other ( Box :: new ( RequiredOptionalScorer :: <
278+ _ ,
279+ _ ,
280+ TScoreCombiner ,
281+ > :: new (
228282 must_scorer,
229283 into_box_scorer ( should_scorer, & score_combiner_fn, num_docs) ,
230- ) ,
231- ) )
232- } else {
233- SpecializedScorer :: Other ( must_scorer )
284+ ) ) )
285+ } else {
286+ SpecializedScorer :: Other ( must_scorer )
287+ }
234288 }
235289 }
236- ( CombinationMethod :: Required ( should_scorer) , Some ( mut must_scorers) ) => {
237- must_scorers. push ( into_box_scorer ( should_scorer, & score_combiner_fn, num_docs) ) ;
238- SpecializedScorer :: Other ( intersect_scorers ( must_scorers, num_docs) )
239- }
240- ( CombinationMethod :: Ignored , None ) => {
241- return Ok ( SpecializedScorer :: Other ( Box :: new ( EmptyScorer ) ) )
290+ ( ShouldScorersCombinationMethod :: Required ( should_scorer) , mut must_scorers) => {
291+ if must_scorers. is_empty ( ) {
292+ should_scorer
293+ } else {
294+ must_scorers. push ( into_box_scorer ( should_scorer, & score_combiner_fn, num_docs) ) ;
295+ SpecializedScorer :: Other ( intersect_scorers ( must_scorers, num_docs) )
296+ }
242297 }
243- ( CombinationMethod :: Required ( should_scorer) , None ) => should_scorer,
244- // Optional options are promoted to required if no must scorers exists.
245- ( CombinationMethod :: Optional ( should_scorer) , None ) => should_scorer,
246298 } ;
247299 if let Some ( exclude_scorer) = exclude_scorer_opt {
248- let positive_scorer_boxed =
249- into_box_scorer ( positive_scorer , & score_combiner_fn, num_docs) ;
300+ let include_scorer_boxed =
301+ into_box_scorer ( include_scorer , & score_combiner_fn, num_docs) ;
250302 Ok ( SpecializedScorer :: Other ( Box :: new ( Exclude :: new (
251- positive_scorer_boxed ,
303+ include_scorer_boxed ,
252304 exclude_scorer,
253305 ) ) ) )
254306 } else {
255- Ok ( positive_scorer )
307+ Ok ( include_scorer )
256308 }
257309 }
258310}
259311
312+ #[ derive( Default , Copy , Clone , Debug ) ]
313+ struct AllAndEmptyScorerCounts {
314+ num_all_scorers : usize ,
315+ num_empty_scorers : usize ,
316+ }
317+
318+ fn remove_and_count_all_and_empty_scorers (
319+ scorers : & mut Vec < Box < dyn Scorer > > ,
320+ ) -> AllAndEmptyScorerCounts {
321+ let mut counts = AllAndEmptyScorerCounts :: default ( ) ;
322+ scorers. retain ( |scorer| {
323+ if scorer. is :: < AllScorer > ( ) {
324+ counts. num_all_scorers += 1 ;
325+ false
326+ } else if scorer. is :: < EmptyScorer > ( ) {
327+ counts. num_empty_scorers += 1 ;
328+ false
329+ } else {
330+ true
331+ }
332+ } ) ;
333+ counts
334+ }
335+
260336impl < TScoreCombiner : ScoreCombiner + Sync > Weight for BooleanWeight < TScoreCombiner > {
261337 fn scorer ( & self , reader : & SegmentReader , boost : Score ) -> crate :: Result < Box < dyn Scorer > > {
262338 let num_docs = reader. num_docs ( ) ;
@@ -293,7 +369,7 @@ impl<TScoreCombiner: ScoreCombiner + Sync> Weight for BooleanWeight<TScoreCombin
293369
294370 let mut explanation = Explanation :: new ( "BooleanClause. sum of ..." , scorer. score ( ) ) ;
295371 for ( occur, subweight) in & self . weights {
296- if is_positive_occur ( * occur) {
372+ if is_include_occur ( * occur) {
297373 if let Ok ( child_explanation) = subweight. explain ( reader, doc) {
298374 explanation. add_detail ( child_explanation) ;
299375 }
@@ -377,7 +453,7 @@ impl<TScoreCombiner: ScoreCombiner + Sync> Weight for BooleanWeight<TScoreCombin
377453 }
378454}
379455
380- fn is_positive_occur ( occur : Occur ) -> bool {
456+ fn is_include_occur ( occur : Occur ) -> bool {
381457 match occur {
382458 Occur :: Must | Occur :: Should => true ,
383459 Occur :: MustNot => false ,
0 commit comments