diff --git a/milli/src/search/criteria/exactness.rs b/milli/src/search/criteria/exactness.rs index a67b9ed3c..e7ece6e91 100644 --- a/milli/src/search/criteria/exactness.rs +++ b/milli/src/search/criteria/exactness.rs @@ -150,7 +150,25 @@ fn resolve_state( { use State::*; match state { - ExactAttribute(mut allowed_candidates) | + ExactAttribute(mut allowed_candidates) => { + let query_len = query.len() as u32; + let mut candidates = RoaringBitmap::new(); + let attributes_ids = ctx.searchable_fields_ids()?; + for id in attributes_ids { + if let Some(attribute_allowed_docids) = ctx.field_id_len_docids(id, query_len)? { + let mut attribute_candidates_array = attribute_start_with_docids(ctx, id as u32, query)?; + attribute_candidates_array.push(attribute_allowed_docids); + candidates |= intersection_of(attribute_candidates_array.iter().collect()); + } + } + + // only keep allowed candidates + candidates &= &allowed_candidates; + // remove current candidates from allowed candidates + allowed_candidates -= &candidates; + Ok((candidates, Some(AttributeStartsWith(allowed_candidates)))) + + }, AttributeStartsWith(mut allowed_candidates) => { let mut candidates = RoaringBitmap::new(); let attributes_ids = ctx.searchable_fields_ids()?; diff --git a/milli/src/search/criteria/mod.rs b/milli/src/search/criteria/mod.rs index 1c626e183..d2fd808f9 100644 --- a/milli/src/search/criteria/mod.rs +++ b/milli/src/search/criteria/mod.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use anyhow::bail; use roaring::RoaringBitmap; -use crate::{TreeLevel, search::{word_derivations, WordDerivationsCache}}; +use crate::{FieldId, TreeLevel, search::{word_derivations, WordDerivationsCache}}; use crate::{Index, DocumentId}; use super::query_tree::{Operation, PrimitiveQuery, PrimitiveQueryPart, Query, QueryKind}; @@ -84,7 +84,8 @@ pub trait Context<'c> { fn word_position_iterator(&self, word: &str, level: TreeLevel, in_prefix_cache: bool, left: Option, right: Option) -> heed::Result> + 'c>>; fn word_position_last_level(&self, word: &str, in_prefix_cache: bool) -> heed::Result>; fn synonyms(&self, word: &str) -> heed::Result>>>; - fn searchable_fields_ids(&self) -> heed::Result>; + fn searchable_fields_ids(&self) -> heed::Result>; + fn field_id_len_docids(&self, field_id: FieldId, len: u32) -> heed::Result>; fn word_level_position_docids(&self, word: &str, level: TreeLevel, left: u32, right: u32) -> Result, heed::Error>; } pub struct CriteriaBuilder<'t> { @@ -180,12 +181,15 @@ impl<'c> Context<'c> for CriteriaBuilder<'c> { self.index.words_synonyms(self.rtxn, &[word]) } - fn searchable_fields_ids(&self) -> heed::Result> { + fn searchable_fields_ids(&self) -> heed::Result> { match self.index.searchable_fields_ids(self.rtxn)? { Some(searchable_fields_ids) => Ok(searchable_fields_ids), None => Ok(self.index.fields_ids_map(self.rtxn)?.ids().collect()), } + } + fn field_id_len_docids(&self, field_id: FieldId, len: u32) -> heed::Result> { + Ok(None) } fn word_level_position_docids(&self, word: &str, level: TreeLevel, left: u32, right: u32) -> Result, heed::Error> { @@ -486,13 +490,17 @@ pub mod test { todo!() } - fn searchable_fields_ids(&self) -> heed::Result> { + fn searchable_fields_ids(&self) -> heed::Result> { todo!() } fn word_level_position_docids(&self, word: &str, level: TreeLevel, left: u32, right: u32) -> Result, heed::Error> { todo!() } + + fn field_id_len_docids(&self, field_id: FieldId, len: u32) -> heed::Result> { + todo!() + } } impl<'a> Default for TestContext<'a> {