From 3772d960ffba3760660f890d07f30cd299a74cf7 Mon Sep 17 00:00:00 2001 From: Francesco Date: Tue, 30 Jan 2024 23:08:28 +0100 Subject: [PATCH] boolean queries and readme --- .gitignore | 2 - README.md | 60 +++++++++---- makefile | 4 +- misc/web.png | Bin 0 -> 137746 bytes search/Cargo.toml | 1 + search/src/engine/mod.rs | 159 ++++++++++++++++++++++++---------- search/src/engine/postings.rs | 3 + search/src/main.rs | 12 ++- server/src/main.rs | 8 +- server/templates/index.html | 6 +- 10 files changed, 180 insertions(+), 75 deletions(-) create mode 100644 misc/web.png diff --git a/.gitignore b/.gitignore index 3192777..7bbb396 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,4 @@ Cargo.lock # TODO todo.md -/misc - .DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 4f917bc..333c87c 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,53 @@ Search engine written in Rust, based on an inverted index on disk. -## Implementation status +## Commands -**IO** -- [x] Classes for writing and reading bit-streams; -- [x] Proper strings writer and reader. +**Index a new document collection** -**Text preprocessing** -- [x] Tokenization; -- [x] Stemming; +``` +make cli folder=path/to/folder action=build min_f=1 max_p=0.99 +``` -**Index construction** -- [x] In-memory datasets index construction; -- [x] Proper vocabulary and paths on disk; -- [x] Spelling correction index; -- [x] Min and max frequency cutoffs. +The `min_f` param filters terms appearing less that it, while `max_p` filters terms appearing more than +in `max_p` percentage of the documents. -**Queries** -- [x] BM25 scoring and query window; -- [ ] Boolean queries: in progress +The folder param is a path to a folder with the following structure: +``` +├── docs +│ ├── 1.txt +│ ├── 2.txt +│ └── 3.txt +└── index + ├── idx.alphas + ├── idx.docs + ├── idx.offsets + └── idx.postings +``` -**Client** -- [x] CLI; -- [x] Web interface. +The index folder will be created after the build command. + +**Load a document collection** + +You can load a pre-build index by running: + +``` +make web folder=path/to/folder +``` + +You can then visit `http://0.0.0.0:3000` to find a web interface to enter free text and boolean queries. + +![web.png](misc%2Fweb.png) + +**Query Syntax** + +You can perform Google-like free test queries, results will +be ranked via [BM25](https://en.wikipedia.org/wiki/Okapi_BM25) scoring. + +You can also specify boolean queries with `"b: "` prefix such as: +``` +b: hello AND there OR NOT man +``` ## References [Introduction to Information Retrieval](https://nlp.stanford.edu/IR-book/information-retrieval-book.html) - Christopher D. Manning, Prabhakar Raghavan and Hinrich Schütze diff --git a/makefile b/makefile index f9d463d..af94106 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,8 @@ web: - cargo run --release --bin server $(index_name) + cargo run --release --bin server ${folder} cli: - cargo run --release --bin search $(index_name) ${action} + cargo run --release --bin search ${folder} ${action} ${min_f} ${max_p} test: cargo test --release diff --git a/misc/web.png b/misc/web.png new file mode 100644 index 0000000000000000000000000000000000000000..cfaa888107f7eb2ddf27c4764fc55306ea01b9e0 GIT binary patch literal 137746 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%0Am46T+JJmpRV_Itw(DChZv0&H6Rf2G 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

TL{MBOPXC^G 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 OqadRyoq6)yjsFGeL7d3| literal 0 HcmV?d00001 diff --git a/search/Cargo.toml b/search/Cargo.toml index bd4693e..4b0d297 100644 --- a/search/Cargo.toml +++ b/search/Cargo.toml @@ -13,3 +13,4 @@ fxhash = "0.2.1" tempdir = "0.3.7" regex = "1" argparse = "0.2.2" +phf = { version = "0.11.2", features = ["macros"] } diff --git a/search/src/engine/mod.rs b/search/src/engine/mod.rs index 1734454..0e8b248 100644 --- a/search/src/engine/mod.rs +++ b/search/src/engine/mod.rs @@ -11,6 +11,7 @@ use self::heap::FixedMinHeap; use self::postings::{DocumentIdsList, Postings, PostingsList}; use self::preprocessor::Preprocessor; use self::vocabulary::Vocabulary; +use phf::phf_map; use std::cmp::min; use std::collections::{BTreeMap, HashMap}; use std::time::Instant; @@ -26,6 +27,14 @@ const BM25_SCORE_MULTIPLIER: f64 = 1.0; const BM25_KL: f64 = 1.2; const BM25_B: f64 = 0.75; +static BOOLEAN_PRECEDENCE: phf::Map<&'static str, &u8> = phf_map! { + "NOT" => &3, + "AND" => &2, + "OR" => &1, + "(" => &0, + ")" => &0, +}; + pub struct Engine { vocabulary: Vocabulary, postings: Postings, @@ -39,19 +48,13 @@ pub struct InMemory { documents: Vec, } -pub struct BooleanQueryResult { - pub postfix_query: Vec, - pub documents_ids: DocumentIdsList, - pub time_ms: u128, -} - -pub struct RankedQueryResult { - pub tokens: Vec, - pub documents: Vec, +pub struct QueryResult { + pub query: Vec, + pub documents: Vec, pub time_ms: u128, } -pub struct RankedDocumentResult { +pub struct DocumentResult { pub id: u32, pub path: String, pub score: f64, @@ -88,15 +91,16 @@ impl Engine { } } - pub fn boolean_query(&mut self, postfix_expression: Vec<&str>) -> BooleanQueryResult { + pub fn boolean_query(&mut self, query: &str) -> QueryResult { let start_time = Instant::now(); let mut stack = Vec::new(); let mut intermediate_result; let num_docs = self.documents.get_num_documents(); - for p in postfix_expression.clone() { - match p { + let query = Self::infix_to_postfix_boolean(query); + for p in query.clone() { + match p.as_str() { "AND" => { intermediate_result = Postings::and_operator(stack.pop().unwrap(), stack.pop().unwrap()); @@ -111,7 +115,7 @@ impl Engine { _ => { intermediate_result = self .vocabulary - .spellcheck_term(p) + .spellcheck_term(&p) .and_then(|t| self.get_term_doc_ids(&t)) .unwrap_or_default(); } @@ -120,16 +124,27 @@ impl Engine { stack.push(intermediate_result); } + let documents = stack + .pop() + .unwrap() + .iter() + .map(|i| DocumentResult { + id: *i, + path: self.documents.get_doc_path(*i), + score: 1.0, + }) + .collect(); + let time_ms = start_time.elapsed().as_millis(); - BooleanQueryResult { - postfix_query: postfix_expression.iter().map(|s| s.to_string()).collect(), - documents_ids: stack.pop().unwrap(), + QueryResult { + query, + documents, time_ms, } } - pub fn free_query(&mut self, query: &str, num_results: usize) -> RankedQueryResult { + pub fn free_query(&mut self, query: &str, num_results: usize) -> QueryResult { let start_time = Instant::now(); let tokens: Vec = self @@ -184,7 +199,7 @@ impl Engine { let documents = selector .get_sorted_id_priority_pairs() .iter() - .map(|(id, score)| RankedDocumentResult { + .map(|(id, score)| DocumentResult { id: *id, score: *score, path: self.documents.get_doc_path(*id), @@ -193,23 +208,57 @@ impl Engine { let time_ms = start_time.elapsed().as_millis(); - RankedQueryResult { - tokens, + QueryResult { + query: tokens, documents, time_ms, } } - fn get_term_postings(&mut self, term: &str) -> Option { + fn get_term_doc_ids(&mut self, term: &str) -> Option { self.vocabulary .get_term_index(term) - .map(|i| self.postings.load_postings_list(i)) + .map(|i| self.postings.load_doc_ids_list(i)) } - fn get_term_doc_ids(&mut self, term: &str) -> Option { + fn infix_to_postfix_boolean(query: &str) -> Vec { + let mut res = Vec::new(); + let mut stack = Vec::new(); + + let sanitized_query = query.replace('(', " ( ").replace(')', " ) "); + + for t in sanitized_query.split_ascii_whitespace() { + if t == "(" { + stack.push(t); + } else if t == ")" { + let mut last = stack.pop().unwrap(); + while last != "(" { + res.push(last); + last = stack.pop().unwrap(); + } + } else if let Some(current_precedence) = BOOLEAN_PRECEDENCE.get(t) { + while !stack.is_empty() { + let last = stack.last().unwrap(); + if BOOLEAN_PRECEDENCE.get(last).unwrap() > current_precedence { + res.push(stack.pop().unwrap()); + } else { + break; + } + } + stack.push(t); + } else { + res.push(t); + } + } + + stack.iter().rev().for_each(|e| res.push(e)); + res.iter().map(|s| (*s).to_string()).collect() + } + + fn get_term_postings(&mut self, term: &str) -> Option { self.vocabulary .get_term_index(term) - .map(|i| self.postings.load_doc_ids_list(i)) + .map(|i| self.postings.load_postings_list(i)) } fn compute_score(document_score: &DocumentScore, num_tokens: usize) -> f64 { @@ -254,37 +303,59 @@ mod test { #[test] fn test_build() { let index_path = &create_temporary_dir_path(); - Engine::build_engine("test_data/docs", index_path, 1.0, 0); - let mut idx = Engine::load_index(index_path); for ele in ["hello", "man", "world"] { assert!(idx.vocabulary.get_term_index(ele).is_some()); } - let mut query: Vec = idx + let mut free_query: Vec = idx .free_query("hello", 10) .documents .iter() .map(|d| d.path.clone()) .collect(); + free_query.sort(); + + assert_eq!(free_query, ["test_data/docs/1.txt", "test_data/docs/2.txt"]); + + let mut boolean_query: Vec = idx + .boolean_query("hello AND NOT world") + .documents + .iter() + .map(|d| d.path.clone()) + .collect(); + boolean_query.sort(); - query.sort(); - - assert_eq!(query, ["test_data/docs/1.txt", "test_data/docs/2.txt"]); - - // println!( - // "{:?}", - // idx.boolean_query(vec!["hello", "man", "OR"]).documents_ids - // ); - // println!( - // "{:?}", - // idx.boolean_query(vec!["hello", "man", "AND"]).documents_ids - // ); - // println!( - // "{:?}", - // idx.boolean_query(vec!["man", "NOT"]).documents_ids[0] - // ); + assert_eq!(boolean_query, ["test_data/docs/2.txt"]); + } + + #[test] + fn test_infix_postfix() { + assert_eq!( + Engine::infix_to_postfix_boolean("a AND (b OR NOT c)"), + ["a", "b", "c", "NOT", "OR", "AND"] + ); + + assert_eq!( + Engine::infix_to_postfix_boolean("a AND b OR NOT c"), + ["a", "b", "AND", "c", "NOT", "OR"] + ); + + assert_eq!( + Engine::infix_to_postfix_boolean("NOT (a AND b) OR NOT (c OR d)"), + ["a", "b", "AND", "NOT", "c", "d", "OR", "NOT", "OR"] + ); + + assert_eq!( + Engine::infix_to_postfix_boolean("a AND b AND c OR d OR e"), + ["a", "b", "c", "AND", "AND", "d", "e", "OR", "OR"] + ); + + assert_eq!( + Engine::infix_to_postfix_boolean("a AND (b OR c)"), + ["a", "b", "c", "OR", "AND"] + ); } } diff --git a/search/src/engine/postings.rs b/search/src/engine/postings.rs index b238025..8402869 100644 --- a/search/src/engine/postings.rs +++ b/search/src/engine/postings.rs @@ -241,5 +241,8 @@ mod tests { let result_empty = Postings::not_operator(vec![], n); assert_eq!(result_empty, (1..=n).collect::>()); + + let result_full = Postings::not_operator(vec![0, 1, 2], 3); + assert_eq!(result_full, []); } } diff --git a/search/src/main.rs b/search/src/main.rs index 7255302..450e53a 100644 --- a/search/src/main.rs +++ b/search/src/main.rs @@ -1,5 +1,5 @@ use indicatif::HumanDuration; -use search::engine::{Engine, RankedQueryResult}; +use search::engine::{Engine, QueryResult}; use std::cmp::min; use std::env; use std::io::{self, Write}; @@ -9,8 +9,8 @@ use std::time::{Duration, Instant}; const NUM_TOP_RESULTS: usize = 10; const NUM_RESULTS: usize = 100; -fn print_results(result: &RankedQueryResult) { - println!("Search tokens: {:?}", result.tokens); +fn print_results(result: &QueryResult) { + println!("Search tokens: {:?}", result.query); if result.documents.is_empty() { println!("\nNo documents found\n"); @@ -107,7 +107,11 @@ fn main() { loop { let query = read_line("> "); - let result = e.free_query(&query, NUM_RESULTS); + let result = if query.starts_with("b: ") { + e.boolean_query(&query.replace("b: ", "")) + } else { + e.free_query(&query, NUM_RESULTS) + }; print_results(&result); } diff --git a/server/src/main.rs b/server/src/main.rs index 3869123..c5efcd7 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -129,7 +129,11 @@ async fn post_query( let mut engine = state.engine.lock().unwrap(); - let query_result = engine.free_query(&payload.query, 100); + let query_result = if payload.query.starts_with("b: ") { + engine.boolean_query(&payload.query.replace("b: ", "")) + } else { + engine.free_query(&payload.query, 100) + }; let documents = query_result .documents @@ -143,7 +147,7 @@ async fn post_query( .collect(); let response = QueryResponse { - tokens: query_result.tokens, + tokens: query_result.query, documents, time_ms: query_result.time_ms, }; diff --git a/server/templates/index.html b/server/templates/index.html index f71bd64..48058db 100644 --- a/server/templates/index.html +++ b/server/templates/index.html @@ -62,12 +62,12 @@ search-rs - + -