diff options
author | Paul Masurel <paul.masurel@gmail.com> | 2018-08-20 09:21:32 +0900 |
---|---|---|
committer | Paul Masurel <paul.masurel@gmail.com> | 2018-08-20 09:21:32 +0900 |
commit | a0a284fe91c0ca16961875959300fcf917327c43 (patch) | |
tree | 241bcbc9d3b03d26c8a32c7215e746c4cf6ff653 /src | |
parent | 0feeef26843e17d731cd06080d8f2a8f7819bd90 (diff) |
Added a full fledge empty query and relyign on it in QueryParser, instead of using an empty clause.
Diffstat (limited to 'src')
-rw-r--r-- | src/query/empty_query.rs | 81 | ||||
-rw-r--r-- | src/query/mod.rs | 3 | ||||
-rw-r--r-- | src/query/query_parser/query_parser.rs | 33 | ||||
-rw-r--r-- | src/query/scorer.rs | 45 |
4 files changed, 111 insertions, 51 deletions
diff --git a/src/query/empty_query.rs b/src/query/empty_query.rs new file mode 100644 index 0000000..06c15c3 --- /dev/null +++ b/src/query/empty_query.rs @@ -0,0 +1,81 @@ +use super::Scorer; +use DocSet; +use Score; +use DocId; +use query::Query; +use Result; +use Searcher; +use query::Weight; +use SegmentReader; + +/// `EmptyQuery` is a dummy `Query` in which no document matches. +/// +/// It is useful for tests and handling edge cases. +#[derive(Clone, Debug)] +pub struct EmptyQuery; + +impl Query for EmptyQuery { + fn weight(&self, _searcher: &Searcher, _scoring_enabled: bool) -> Result<Box<Weight>> { + Ok(Box::new(EmptyWeight)) + } + + fn count(&self, _searcher: &Searcher) -> Result<usize> { + Ok(0) + } +} + +/// `EmptyWeight` is a dummy `Weight` in which no document matches. +/// +/// It is useful for tests and handling edge cases. +pub struct EmptyWeight; +impl Weight for EmptyWeight { + fn scorer(&self, _reader: &SegmentReader) -> Result<Box<Scorer>> { + Ok(Box::new(EmptyScorer)) + } +} + +/// `EmptyScorer` is a dummy `Scorer` in which no document matches. +/// +/// It is useful for tests and handling edge cases. +pub struct EmptyScorer; + +impl DocSet for EmptyScorer { + fn advance(&mut self) -> bool { + false + } + + fn doc(&self) -> DocId { + panic!( + "You may not call .doc() on a scorer \ + where the last call to advance() did not return true." + ); + } + + fn size_hint(&self) -> u32 { + 0 + } +} + +impl Scorer for EmptyScorer { + fn score(&mut self) -> Score { + 0f32 + } +} + +#[cfg(test)] +mod tests { + use query::EmptyScorer; + use DocSet; + + #[test] + fn test_empty_scorer() { + let mut empty_scorer = EmptyScorer; + assert!(!empty_scorer.advance()); + } + + #[test] + #[should_panic] + fn test_empty_scorer_panic_on_doc_call() { + EmptyScorer.doc(); + } +} diff --git a/src/query/mod.rs b/src/query/mod.rs index 7b6368c..7546465 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -3,6 +3,7 @@ Query */ mod all_query; +mod empty_query; mod automaton_weight; mod bitset; mod bm25; @@ -34,6 +35,7 @@ pub use self::union::Union; pub use self::vec_docset::VecDocSet; pub use self::all_query::{AllQuery, AllScorer, AllWeight}; +pub use self::empty_query::{EmptyQuery, EmptyWeight, EmptyScorer}; pub use self::automaton_weight::AutomatonWeight; pub use self::bitset::BitSetDocSet; pub use self::boolean_query::BooleanQuery; @@ -49,7 +51,6 @@ pub use self::range_query::RangeQuery; pub use self::regex_query::RegexQuery; pub use self::reqopt_scorer::RequiredOptionalScorer; pub use self::scorer::ConstScorer; -pub use self::scorer::EmptyScorer; pub use self::scorer::Scorer; pub use self::term_query::TermQuery; pub use self::weight::Weight; diff --git a/src/query/query_parser/query_parser.rs b/src/query/query_parser/query_parser.rs index 0b41334..abe6b40 100644 --- a/src/query/query_parser/query_parser.rs +++ b/src/query/query_parser/query_parser.rs @@ -18,6 +18,7 @@ use std::ops::Bound; use std::str::FromStr; use tokenizer::TokenizerManager; use combine::Parser; +use query::EmptyQuery; /// Possible error that may happen when parsing a query. @@ -438,11 +439,15 @@ fn convert_literal_to_query(logical_literal: LogicalLiteral) -> Box<Query> { fn convert_to_query(logical_ast: LogicalAST) -> Box<Query> { match logical_ast { LogicalAST::Clause(clause) => { - let occur_subqueries = clause - .into_iter() - .map(|(occur, subquery)| (occur, convert_to_query(subquery))) - .collect::<Vec<_>>(); - Box::new(BooleanQuery::from(occur_subqueries)) + if clause.is_empty() { + Box::new(EmptyQuery) + } else { + let occur_subqueries = clause + .into_iter() + .map(|(occur, subquery)| (occur, convert_to_query(subquery))) + .collect::<Vec<_>>(); + Box::new(BooleanQuery::from(occur_subqueries)) + } } LogicalAST::Leaf(logical_literal) => convert_literal_to_query(*logical_literal), } @@ -542,6 +547,24 @@ mod test { } #[test] + pub fn test_parse_query_empty() { + test_parse_query_to_logical_ast_helper( + "", + "<emptyclause>", + false, + ); + test_parse_query_to_logical_ast_helper( + " ", + "<emptyclause>", + false, + ); + let query_parser = make_query_parser(); + let query_result = query_parser.parse_query(""); + let query = query_result.unwrap(); + assert_eq!(format!("{:?}", query), "EmptyQuery"); + } + + #[test] pub fn test_parse_query_ints() { let query_parser = make_query_parser(); assert!(query_parser.parse_query("signed:2324").is_ok()); diff --git a/src/query/scorer.rs b/src/query/scorer.rs index a94b03a..186e75a 100644 --- a/src/query/scorer.rs +++ b/src/query/scorer.rs @@ -50,33 +50,6 @@ impl Scorer for Box<Scorer> { } } -/// `EmptyScorer` is a dummy `Scorer` in which no document matches. -/// -/// It is useful for tests and handling edge cases. -pub struct EmptyScorer; - -impl DocSet for EmptyScorer { - fn advance(&mut self) -> bool { - false - } - - fn doc(&self) -> DocId { - panic!( - "You may not call .doc() on a scorer \ - where the last call to advance() did not return true." - ); - } - - fn size_hint(&self) -> u32 { - 0 - } -} - -impl Scorer for EmptyScorer { - fn score(&mut self) -> Score { - 0f32 - } -} /// Wraps a `DocSet` and simply returns a constant `Scorer`. /// The `ConstScorer` is useful if you have a `DocSet` where @@ -135,21 +108,3 @@ impl<TDocSet: DocSet + 'static> Scorer for ConstScorer<TDocSet> { 1f32 } } - -#[cfg(test)] -mod tests { - use super::EmptyScorer; - use DocSet; - - #[test] - fn test_empty_scorer() { - let mut empty_scorer = EmptyScorer; - assert!(!empty_scorer.advance()); - } - - #[test] - #[should_panic] - fn test_empty_scorer_panic_on_doc_call() { - EmptyScorer.doc(); - } -} |