diff --git a/milli/src/search/criteria/fetcher.rs b/milli/src/search/criteria/fetcher.rs index f0cf16b90..38fee20d3 100644 --- a/milli/src/search/criteria/fetcher.rs +++ b/milli/src/search/criteria/fetcher.rs @@ -56,7 +56,7 @@ impl<'t> Criterion for Fetcher<'t> { let should_get_documents_ids = take(&mut self.should_get_documents_ids); match &mut self.candidates { - Allowed(candidates) => { + Allowed(_) => { let candidates = take(&mut self.candidates).into_inner(); let candidates = match &self.query_tree { Some(qt) if should_get_documents_ids => { diff --git a/milli/src/search/criteria/mod.rs b/milli/src/search/criteria/mod.rs index 1845e607a..49bacf209 100644 --- a/milli/src/search/criteria/mod.rs +++ b/milli/src/search/criteria/mod.rs @@ -1,13 +1,19 @@ use std::collections::HashMap; use std::borrow::Cow; -use anyhow::bail; +use anyhow::{bail, Context as _}; use roaring::RoaringBitmap; -use crate::Index; +use crate::facet::FacetType; use crate::search::word_derivations; +use crate::{Index, FieldId}; use super::query_tree::{Operation, Query, QueryKind}; +use self::typo::Typo; +use self::words::Words; +use self::asc_desc::AscDesc; +use self::proximity::Proximity; +use self::fetcher::Fetcher; pub mod typo; pub mod words; @@ -62,14 +68,14 @@ pub trait Context { fn words_fst<'t>(&self) -> &'t fst::Set>; fn in_prefix_cache(&self, word: &str) -> bool; } -pub struct HeedContext<'t> { +pub struct CriteriaBuilder<'t> { rtxn: &'t heed::RoTxn<'t>, index: &'t Index, words_fst: fst::Set>, words_prefixes_fst: fst::Set>, } -impl<'a> Context for HeedContext<'a> { +impl<'a> Context for CriteriaBuilder<'a> { fn documents_ids(&self) -> heed::Result { self.index.documents_ids(self.rtxn) } @@ -101,17 +107,71 @@ impl<'a> Context for HeedContext<'a> { } } -impl<'t> HeedContext<'t> { +impl<'t> CriteriaBuilder<'t> { pub fn new(rtxn: &'t heed::RoTxn<'t>, index: &'t Index) -> anyhow::Result { let words_fst = index.words_fst(rtxn)?; let words_prefixes_fst = index.words_prefixes_fst(rtxn)?; + Ok(Self { rtxn, index, words_fst, words_prefixes_fst }) + } - Ok(Self { - rtxn, - index, - words_fst, - words_prefixes_fst, - }) + pub fn build( + &'t self, + mut query_tree: Option, + mut facet_candidates: Option, + ) -> anyhow::Result> + { + use crate::criterion::Criterion as Name; + + let fields_ids_map = self.index.fields_ids_map(&self.rtxn)?; + let faceted_fields = self.index.faceted_fields(&self.rtxn)?; + let field_id_facet_type = |field: &str| -> anyhow::Result<(FieldId, FacetType)> { + let id = fields_ids_map.id(field).with_context(|| { + format!("field {:?} isn't registered", field) + })?; + let facet_type = faceted_fields.get(field).with_context(|| { + format!("field {:?} isn't faceted", field) + })?; + Ok((id, *facet_type)) + }; + + let mut criterion = None as Option>; + for name in self.index.criteria(&self.rtxn)? { + criterion = Some(match criterion.take() { + Some(father) => match name { + Name::Typo => Box::new(Typo::new(self, father)?), + Name::Words => Box::new(Words::new(self, father)?), + Name::Proximity => Box::new(Proximity::new(self, father)?), + Name::Asc(field) => { + let (id, facet_type) = field_id_facet_type(&field)?; + Box::new(AscDesc::asc(&self.index, &self.rtxn, father, id, facet_type)?) + }, + Name::Desc(field) => { + let (id, facet_type) = field_id_facet_type(&field)?; + Box::new(AscDesc::desc(&self.index, &self.rtxn, father, id, facet_type)?) + }, + _otherwise => father, + }, + None => match name { + Name::Typo => Box::new(Typo::initial(self, query_tree.take(), facet_candidates.take())?), + Name::Words => Box::new(Words::initial(self, query_tree.take(), facet_candidates.take())?), + Name::Proximity => Box::new(Proximity::initial(self, query_tree.take(), facet_candidates.take())?), + Name::Asc(field) => { + let (id, facet_type) = field_id_facet_type(&field)?; + Box::new(AscDesc::initial_asc(&self.index, &self.rtxn, query_tree.take(), facet_candidates.take(), id, facet_type)?) + }, + Name::Desc(field) => { + let (id, facet_type) = field_id_facet_type(&field)?; + Box::new(AscDesc::initial_desc(&self.index, &self.rtxn, query_tree.take(), facet_candidates.take(), id, facet_type)?) + }, + _otherwise => continue, + }, + }); + } + + match criterion { + Some(criterion) => Ok(Fetcher::new(self, criterion)), + None => Ok(Fetcher::initial(self, query_tree, facet_candidates)), + } } } diff --git a/milli/src/search/mod.rs b/milli/src/search/mod.rs index 84c6acf3e..48b0f71da 100644 --- a/milli/src/search/mod.rs +++ b/milli/src/search/mod.rs @@ -10,7 +10,6 @@ use once_cell::sync::Lazy; use roaring::bitmap::RoaringBitmap; use crate::search::criteria::{Criterion, CriterionResult}; -use crate::search::criteria::{typo::Typo, words::Words, proximity::Proximity, fetcher::Fetcher}; use crate::{Index, DocumentId}; pub use self::facet::FacetIter; @@ -92,12 +91,8 @@ impl<'a> Search<'a> { None => MatchingWords::default(), }; - let criteria_ctx = criteria::HeedContext::new(self.rtxn, self.index)?; - let typo_criterion = Typo::initial(&criteria_ctx, query_tree, facet_candidates)?; - let words_criterion = Words::new(&criteria_ctx, Box::new(typo_criterion))?; - let proximity_criterion = Proximity::new(&criteria_ctx, Box::new(words_criterion))?; - let fetcher_criterion = Fetcher::new(&criteria_ctx, Box::new(proximity_criterion)); - let mut criteria = fetcher_criterion; + let criteria_builder = criteria::CriteriaBuilder::new(self.rtxn, self.index)?; + let mut criteria = criteria_builder.build(query_tree, facet_candidates)?; // // We sort in descending order on a specific field *by hand*, don't do that at home. // let attr_name = "released-timestamp";