diff --git a/src/collector/chained_collector.rs b/src/collector/chained_collector.rs index 89f872516..04d898425 100644 --- a/src/collector/chained_collector.rs +++ b/src/collector/chained_collector.rs @@ -16,6 +16,10 @@ impl Collector for DoNothingCollector { } #[inline] fn collect(&mut self, _doc: DocId, _score: Score) {} + #[inline] + fn requires_scoring(&self) -> bool { + false + } } /// Zero-cost abstraction used to collect on multiple collectors. @@ -51,6 +55,10 @@ impl Collector for ChainedCollector bool { + self.left.requires_scoring() || self.right.requires_scoring() + } } /// Creates a `ChainedCollector` diff --git a/src/collector/count_collector.rs b/src/collector/count_collector.rs index 15363e33a..57b11a61f 100644 --- a/src/collector/count_collector.rs +++ b/src/collector/count_collector.rs @@ -28,6 +28,10 @@ impl Collector for CountCollector { fn collect(&mut self, _: DocId, _: Score) { self.count += 1; } + + fn requires_scoring(&self) -> bool { + false + } } #[cfg(test)] @@ -44,5 +48,8 @@ mod tests { assert_eq!(count_collector.count(), 1); count_collector.collect(1u32, 1f32); assert_eq!(count_collector.count(), 2); + assert!(!count_collector.requires_scoring()); } + + } diff --git a/src/collector/facet_collector.rs b/src/collector/facet_collector.rs index b9efd2660..7329b2471 100644 --- a/src/collector/facet_collector.rs +++ b/src/collector/facet_collector.rs @@ -420,6 +420,10 @@ impl Collector for FacetCollector { previous_collapsed_ord = collapsed_ord; } } + + fn requires_scoring(&self) -> bool { + false + } } /// Intermediary result of the `FacetCollector` that stores diff --git a/src/collector/mod.rs b/src/collector/mod.rs index 6fa5dc75a..218ead2e9 100644 --- a/src/collector/mod.rs +++ b/src/collector/mod.rs @@ -62,6 +62,9 @@ pub trait Collector { ) -> Result<()>; /// The query pushes the scored document to the collector via this method. fn collect(&mut self, doc: DocId, score: Score); + + /// Returns true iff the collector requires to compute scores for documents. + fn requires_scoring(&self) -> bool; } impl<'a, C: Collector> Collector for &'a mut C { @@ -74,7 +77,11 @@ impl<'a, C: Collector> Collector for &'a mut C { } /// The query pushes the scored document to the collector via this method. fn collect(&mut self, doc: DocId, score: Score) { - (*self).collect(doc, score); + C::collect(self, doc, score) + } + + fn requires_scoring(&self) -> bool { + C::requires_scoring(self) } } @@ -128,6 +135,10 @@ pub mod tests { fn collect(&mut self, doc: DocId, _score: Score) { self.docs.push(doc + self.offset); } + + fn requires_scoring(&self) -> bool { + false + } } /// Collects in order all of the fast fields for all of the @@ -144,7 +155,7 @@ pub mod tests { pub fn for_field(field: Field) -> FastFieldTestCollector { FastFieldTestCollector { vals: Vec::new(), - field: field, + field, ff_reader: None, } } @@ -164,6 +175,9 @@ pub mod tests { let val = self.ff_reader.as_ref().unwrap().get(doc); self.vals.push(val); } + fn requires_scoring(&self) -> bool { + false + } } #[bench] diff --git a/src/collector/multi_collector.rs b/src/collector/multi_collector.rs index fc5c98afb..d3f980adc 100644 --- a/src/collector/multi_collector.rs +++ b/src/collector/multi_collector.rs @@ -17,7 +17,7 @@ impl<'a> MultiCollector<'a> { /// Constructor pub fn from(collectors: Vec<&'a mut Collector>) -> MultiCollector { MultiCollector { - collectors: collectors, + collectors, } } } @@ -39,6 +39,11 @@ impl<'a> Collector for MultiCollector<'a> { collector.collect(doc, score); } } + fn requires_scoring(&self) -> bool { + self.collectors + .iter() + .any(|collector| collector.requires_scoring()) + } } #[cfg(test)] diff --git a/src/collector/top_collector.rs b/src/collector/top_collector.rs index 897386019..1a411b6d4 100644 --- a/src/collector/top_collector.rs +++ b/src/collector/top_collector.rs @@ -125,6 +125,10 @@ impl Collector for TopCollector { self.heap.push(wrapped_doc); } } + + fn requires_scoring(&self) -> bool { + true + } } #[cfg(test)] diff --git a/src/postings/mod.rs b/src/postings/mod.rs index d4570475f..a637314fb 100644 --- a/src/postings/mod.rs +++ b/src/postings/mod.rs @@ -95,14 +95,14 @@ pub mod tests { index_writer.add_document(doc!(title => r#"abc abc abc"#)); } index_writer.add_document(doc!(title => r#"abc be be be be abc"#)); - index_writer.commit().unwrap(); + index_writer .commit().unwrap(); index.load_searchers().unwrap(); let searcher = index.searcher(); let query = TermQuery::new( Term::from_field_text(title, "abc"), IndexRecordOption::WithFreqsAndPositions, ); - let weight = query.specialized_weight(&*searcher); + let weight = query.specialized_weight(&*searcher, true); { let mut scorer = weight .specialized_scorer(searcher.segment_reader(0u32)) @@ -282,7 +282,7 @@ pub mod tests { IndexRecordOption::Basic, ); let searcher = index.searcher(); - let mut term_weight = term_query.specialized_weight(&*searcher); + let mut term_weight = term_query.specialized_weight(&*searcher, true); term_weight.index_record_option = IndexRecordOption::WithFreqsAndPositions; let segment_reader = &searcher.segment_readers()[0]; let mut term_scorer = term_weight.specialized_scorer(segment_reader).unwrap(); diff --git a/src/query/all_query.rs b/src/query/all_query.rs index 4e8fe71dc..226a3689f 100644 --- a/src/query/all_query.rs +++ b/src/query/all_query.rs @@ -20,7 +20,7 @@ impl Query for AllQuery { self } - fn weight(&self, _: &Searcher) -> Result> { + fn weight(&self, _: &Searcher, _: bool) -> Result> { Ok(box AllWeight) } } diff --git a/src/query/boolean_query/boolean_query.rs b/src/query/boolean_query/boolean_query.rs index 18ceff404..eae85efbc 100644 --- a/src/query/boolean_query/boolean_query.rs +++ b/src/query/boolean_query/boolean_query.rs @@ -22,14 +22,12 @@ use query::Occur; #[derive(Debug)] pub struct BooleanQuery { subqueries: Vec<(Occur, Box)>, - scoring_disabled: bool, } impl From)>> for BooleanQuery { fn from(subqueries: Vec<(Occur, Box)>) -> BooleanQuery { BooleanQuery { - subqueries, - scoring_disabled: false, + subqueries } } } @@ -39,19 +37,12 @@ impl Query for BooleanQuery { self } - fn disable_scoring(&mut self) { - self.scoring_disabled = true; - for &mut (_, ref mut subquery) in &mut self.subqueries { - subquery.disable_scoring(); - } - } - - fn weight(&self, searcher: &Searcher) -> Result> { + fn weight(&self, searcher: &Searcher, scoring_enabled: bool) -> Result> { let sub_weights = self.subqueries .iter() - .map(|&(ref occur, ref subquery)| Ok((*occur, subquery.weight(searcher)?))) + .map(|&(ref occur, ref subquery)| Ok((*occur, subquery.weight(searcher, scoring_enabled)?))) .collect::>()?; - Ok(box BooleanWeight::new(sub_weights, self.scoring_disabled)) + Ok(box BooleanWeight::new(sub_weights, scoring_enabled)) } } diff --git a/src/query/boolean_query/boolean_weight.rs b/src/query/boolean_query/boolean_weight.rs index ab7039d2e..3f97c4f7e 100644 --- a/src/query/boolean_query/boolean_weight.rs +++ b/src/query/boolean_query/boolean_weight.rs @@ -5,7 +5,6 @@ use std::collections::HashMap; use query::EmptyScorer; use query::Scorer; use query::Exclude; -use query::ConstScorer; use query::Occur; use query::RequiredOptionalScorer; use query::score_combiner::{SumWithCoordsCombiner, DoNothingCombiner, ScoreCombiner}; @@ -25,14 +24,14 @@ fn scorer_union<'a, TScoreCombiner>(docsets: Vec>) -> Box)>, - scoring_disabled: bool, + scoring_enabled: bool, } impl BooleanWeight { - pub fn new(weights: Vec<(Occur, Box)>, scoring_disabled: bool) -> BooleanWeight { + pub fn new(weights: Vec<(Occur, Box)>, scoring_enabled: bool) -> BooleanWeight { BooleanWeight { weights, - scoring_disabled, + scoring_enabled, } } @@ -67,10 +66,10 @@ impl BooleanWeight { let positive_scorer: Box = match (should_scorer_opt, must_scorer_opt) { (Some(should_scorer), Some(must_scorer)) => { - if self.scoring_disabled { - must_scorer - } else { + if self.scoring_enabled { box RequiredOptionalScorer::<_,_,TScoreCombiner>::new(must_scorer, should_scorer) + } else { + must_scorer } } (None, Some(must_scorer)) => must_scorer, @@ -99,10 +98,10 @@ impl Weight for BooleanWeight { } else { weight.scorer(reader) } - } else if self.scoring_disabled { - self.complex_scorer::(reader) - } else { + } else if self.scoring_enabled { self.complex_scorer::(reader) + } else { + self.complex_scorer::(reader) } } } diff --git a/src/query/phrase_query/phrase_query.rs b/src/query/phrase_query/phrase_query.rs index 231c9613c..ccdc9b2db 100644 --- a/src/query/phrase_query/phrase_query.rs +++ b/src/query/phrase_query/phrase_query.rs @@ -35,8 +35,8 @@ impl Query for PhraseQuery { /// Create the weight associated to a query. /// /// See [`Weight`](./trait.Weight.html). - fn weight(&self, _searcher: &Searcher) -> Result> { - Ok(box PhraseWeight::from(self.phrase_terms.clone())) + fn weight(&self, _searcher: &Searcher, scoring_enabled: bool) -> Result> { + Ok(box PhraseWeight::new(self.phrase_terms.clone(), scoring_enabled)) } } diff --git a/src/query/phrase_query/phrase_weight.rs b/src/query/phrase_query/phrase_weight.rs index b70ba3747..6bef26f75 100644 --- a/src/query/phrase_query/phrase_weight.rs +++ b/src/query/phrase_query/phrase_weight.rs @@ -9,11 +9,15 @@ use Result; pub struct PhraseWeight { phrase_terms: Vec, + scoring_enabled: bool } -impl From> for PhraseWeight { - fn from(phrase_terms: Vec) -> PhraseWeight { - PhraseWeight { phrase_terms } +impl PhraseWeight { + pub fn new(phrase_terms: Vec, scoring_enabled: bool) -> PhraseWeight { + PhraseWeight { + phrase_terms, + scoring_enabled // TODO compute the phrase freq if scoring is enabled. stop at first match else. + } } } diff --git a/src/query/query.rs b/src/query/query.rs index bad1b970d..b0af34fde 100644 --- a/src/query/query.rs +++ b/src/query/query.rs @@ -45,16 +45,13 @@ pub trait Query: fmt::Debug { /// into a specific type. This is mostly useful for unit tests. fn as_any(&self) -> &Any; - /// Disable scoring. - /// - /// For some query this may improve performance - /// when scoring is not required. - fn disable_scoring(&mut self) {} - /// Create the weight associated to a query. /// + /// If scoring is not required, setting `scoring_enabled` to `false` + /// can increase performances. + /// /// See [`Weight`](./trait.Weight.html). - fn weight(&self, searcher: &Searcher) -> Result>; + fn weight(&self, searcher: &Searcher, scoring_enabled: bool) -> Result>; /// Search works as follows : /// @@ -67,7 +64,8 @@ pub trait Query: fmt::Debug { /// fn search(&self, searcher: &Searcher, collector: &mut Collector) -> Result { let mut timer_tree = TimerTree::default(); - let weight = self.weight(searcher)?; + let scoring_enabled = collector.requires_scoring(); + let weight = self.weight(searcher, scoring_enabled)?; { let mut search_timer = timer_tree.open("search"); for (segment_ord, segment_reader) in searcher.segment_readers().iter().enumerate() { diff --git a/src/query/range_query.rs b/src/query/range_query.rs index 162254e1d..d9192ebc7 100644 --- a/src/query/range_query.rs +++ b/src/query/range_query.rs @@ -133,7 +133,7 @@ impl Query for RangeQuery { self } - fn weight(&self, _searcher: &Searcher) -> Result> { + fn weight(&self, _searcher: &Searcher, _scoring_enabled: bool) -> Result> { Ok(box RangeWeight { field: self.field, left_bound: self.left_bound.clone(), diff --git a/src/query/reqopt_scorer.rs b/src/query/reqopt_scorer.rs index 144cf9b38..569da7421 100644 --- a/src/query/reqopt_scorer.rs +++ b/src/query/reqopt_scorer.rs @@ -1,7 +1,7 @@ use DocId; use DocSet; use query::Scorer; -use query::score_combiner::{ScoreCombiner, SumCombiner}; +use query::score_combiner::ScoreCombiner; use Score; use postings::SkipResult; use std::cmp::Ordering; diff --git a/src/query/term_query/mod.rs b/src/query/term_query/mod.rs index fa4a03094..3d34960dd 100644 --- a/src/query/term_query/mod.rs +++ b/src/query/term_query/mod.rs @@ -46,7 +46,7 @@ mod tests { Term::from_field_text(text_field, "a"), IndexRecordOption::Basic, ); - let term_weight = term_query.weight(&searcher).unwrap(); + let term_weight = term_query.weight(&searcher, true).unwrap(); let segment_reader = searcher.segment_reader(0); let mut term_scorer = term_weight.scorer(segment_reader).unwrap(); assert!(term_scorer.advance()); diff --git a/src/query/term_query/term_query.rs b/src/query/term_query/term_query.rs index 1971fc660..99b42038e 100644 --- a/src/query/term_query/term_query.rs +++ b/src/query/term_query/term_query.rs @@ -36,12 +36,18 @@ impl TermQuery { /// While `.weight(...)` returns a boxed trait object, /// this method return a specific implementation. /// This is useful for optimization purpose. - pub fn specialized_weight(&self, searcher: &Searcher) -> TermWeight { + pub fn specialized_weight(&self, searcher: &Searcher, scoring_enabled: bool) -> TermWeight { + let index_record_option = + if scoring_enabled { + self.index_record_option + } else { + IndexRecordOption::Basic + }; TermWeight { num_docs: searcher.num_docs(), doc_freq: searcher.doc_freq(&self.term), term: self.term.clone(), - index_record_option: self.index_record_option, + index_record_option } } } @@ -51,11 +57,7 @@ impl Query for TermQuery { self } - fn weight(&self, searcher: &Searcher) -> Result> { - Ok(box self.specialized_weight(searcher)) - } - - fn disable_scoring(&mut self) { - self.index_record_option = IndexRecordOption::Basic; + fn weight(&self, searcher: &Searcher, scoring_enabled: bool) -> Result> { + Ok(box self.specialized_weight(searcher, scoring_enabled)) } }