From a00f5850eed4921aea7a0969bfdd3c15142e31fc Mon Sep 17 00:00:00 2001 From: Kerollmops Date: Tue, 6 Oct 2020 14:52:05 +0200 Subject: [PATCH] Add support for placeholder search for empty queries --- public/script.js | 6 ++++++ src/bin/serve.rs | 12 +++++++----- src/lib.rs | 14 ++++++++++---- src/search.rs | 18 ++++++++++-------- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/public/script.js b/public/script.js index e8bac541d..6825c4d9b 100644 --- a/public/script.js +++ b/public/script.js @@ -74,3 +74,9 @@ $('#docs-count').text(function(index, text) { $('#db-size').text(function(index, text) { return filesize(parseInt(text)) }); + +// We trigger the input when we load the script, this way +// we execute a placeholder search when the input is empty. +$(window).on('load', function () { + $('#search').trigger('input'); +}); diff --git a/src/bin/serve.rs b/src/bin/serve.rs index eebfa7a53..082f5fb86 100644 --- a/src/bin/serve.rs +++ b/src/bin/serve.rs @@ -172,7 +172,7 @@ async fn main() -> anyhow::Result<()> { #[derive(Deserialize)] struct QueryBody { - query: String, + query: Option, } let env_cloned = env.clone(); @@ -184,10 +184,12 @@ async fn main() -> anyhow::Result<()> { let before_search = Instant::now(); let rtxn = env_cloned.read_txn().unwrap(); - let SearchResult { found_words, documents_ids } = index.search(&rtxn) - .query(query.query) - .execute() - .unwrap(); + let mut search = index.search(&rtxn); + if let Some(query) = query.query { + search.query(query); + } + + let SearchResult { found_words, documents_ids } = search.execute().unwrap(); let body = match index.headers(&rtxn).unwrap() { Some(headers) => { diff --git a/src/lib.rs b/src/lib.rs index bd707e422..a9ef09162 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ use csv::StringRecord; use fxhash::{FxHasher32, FxHasher64}; use heed::types::*; use heed::{PolyDatabase, Database}; +use roaring::RoaringBitmap; pub use self::search::{Search, SearchResult}; pub use self::criterion::{Criterion, default_criteria}; @@ -61,6 +62,10 @@ impl Index { }) } + pub fn documents_ids(&self, rtxn: &heed::RoTxn) -> anyhow::Result> { + Ok(self.main.get::<_, Str, RoaringBitmapCodec>(rtxn, DOCUMENTS_IDS_KEY)?) + } + pub fn put_headers(&self, wtxn: &mut heed::RwTxn, headers: &StringRecord) -> heed::Result<()> { self.main.put::<_, Str, CsvStringRecordCodec>(wtxn, HEADERS_KEY, headers) } @@ -114,10 +119,11 @@ impl Index { } /// Returns the number of documents indexed in the database. - pub fn number_of_documents<'t>(&self, rtxn: &'t heed::RoTxn) -> anyhow::Result { - let docids = self.main.get::<_, Str, RoaringBitmapCodec>(rtxn, DOCUMENTS_IDS_KEY)? - .with_context(|| format!("Could not find the list of documents ids"))?; - Ok(docids.len() as usize) + pub fn number_of_documents(&self, rtxn: &heed::RoTxn) -> anyhow::Result { + match self.documents_ids(rtxn)? { + Some(docids) => Ok(docids.len() as usize), + None => Ok(0), + } } pub fn search<'a>(&'a self, rtxn: &'a heed::RoTxn) -> Search<'a> { diff --git a/src/search.rs b/src/search.rs index ed4c80bcd..1e2329687 100644 --- a/src/search.rs +++ b/src/search.rs @@ -141,16 +141,18 @@ impl<'a> Search<'a> { }; // Construct the DFAs related to the query words. - // TODO do a placeholder search when query string isn't present. - let dfas = match &self.query { - Some(q) => Self::generate_query_dfas(q), - None => return Ok(Default::default()), + let dfas = match self.query.as_deref().map(Self::generate_query_dfas) { + Some(dfas) if !dfas.is_empty() => dfas, + _ => { + // If the query is not set or results in no DFAs we return a placeholder. + let documents_ids = match self.index.documents_ids(self.rtxn)? { + Some(docids) => docids.iter().take(limit).collect(), + None => Vec::new(), + }; + return Ok(SearchResult { documents_ids, ..Default::default() }) + }, }; - if dfas.is_empty() { - return Ok(Default::default()); - } - let derived_words = self.fetch_words_docids(&fst, dfas)?; let candidates = Self::compute_candidates(&derived_words);