diff --git a/milli/src/index.rs b/milli/src/index.rs index f3411564b..02a1f9d58 100644 --- a/milli/src/index.rs +++ b/milli/src/index.rs @@ -7,7 +7,7 @@ use heed::{Database, PolyDatabase, RoTxn, RwTxn}; use heed::types::*; use roaring::RoaringBitmap; -use crate::error::UserError; +use crate::error::{UserError, FieldIdMapMissingEntry, InternalError}; use crate::{Criterion, default_criteria, FacetDistribution, FieldsDistribution, Search}; use crate::{BEU32, DocumentId, ExternalDocumentsIds, FieldId, Result}; use crate::{ @@ -304,14 +304,25 @@ impl Index { self.main.get::<_, Str, SerdeBincode>>(rtxn, main_key::DISPLAYED_FIELDS_KEY) } - pub fn displayed_fields_ids(&self, rtxn: &RoTxn) -> heed::Result>> { - let fields_ids_map = self.fields_ids_map(rtxn)?; - let ids = self.displayed_fields(rtxn)? - .map(|fields| fields - .into_iter() - .map(|name| fields_ids_map.id(name).expect("Field not found")) - .collect::>()); - Ok(ids) + /// Identical to `displayed_fields`, but returns the ids instead. + pub fn displayed_fields_ids(&self, rtxn: &RoTxn) -> Result>> { + match self.displayed_fields(rtxn)? { + Some(fields) => { + let fields_ids_map = self.fields_ids_map(rtxn)?; + let mut fields_ids = Vec::new(); + for name in fields.into_iter() { + match fields_ids_map.id(name) { + Some(field_id) => fields_ids.push(field_id), + None => return Err(FieldIdMapMissingEntry::FieldName { + field_name: name.to_string(), + process: "Index::displayed_fields_ids", + }.into()), + } + } + Ok(Some(fields_ids)) + }, + None => Ok(None), + } } /* searchable fields */ @@ -333,20 +344,22 @@ impl Index { } /// Identical to `searchable_fields`, but returns the ids instead. - pub fn searchable_fields_ids(&self, rtxn: &RoTxn) -> heed::Result>> { + pub fn searchable_fields_ids(&self, rtxn: &RoTxn) -> Result>> { match self.searchable_fields(rtxn)? { - Some(names) => { - let fields_map = self.fields_ids_map(rtxn)?; - let mut ids = Vec::new(); - for name in names { - let id = fields_map - .id(name) - .ok_or_else(|| format!("field id map must contain {:?}", name)) - .expect("corrupted data: "); - ids.push(id); + Some(fields) => { + let fields_ids_map = self.fields_ids_map(rtxn)?; + let mut fields_ids = Vec::new(); + for name in fields { + match fields_ids_map.id(name) { + Some(field_id) => fields_ids.push(field_id), + None => return Err(FieldIdMapMissingEntry::FieldName { + field_name: name.to_string(), + process: "Index::searchable_fields_ids", + }.into()), + } } - Ok(Some(ids)) - } + Ok(Some(fields_ids)) + }, None => Ok(None), } } @@ -371,21 +384,25 @@ impl Index { )?.unwrap_or_default()) } - /// Same as `filterable_fields`, but returns ids instead. - pub fn filterable_fields_ids(&self, rtxn: &RoTxn) -> heed::Result> { - let filterable_fields = self.filterable_fields(rtxn)?; + /// Identical to `filterable_fields`, but returns ids instead. + pub fn filterable_fields_ids(&self, rtxn: &RoTxn) -> Result> { + let fields = self.filterable_fields(rtxn)?; let fields_ids_map = self.fields_ids_map(rtxn)?; - let filterable_fields = filterable_fields - .iter() - .map(|k| { - fields_ids_map - .id(k) - .ok_or_else(|| format!("{:?} should be present in the field id map", k)) - .expect("corrupted data: ") - }) - .collect(); - Ok(filterable_fields) + let mut fields_ids = HashSet::new(); + for name in fields { + match fields_ids_map.id(&name) { + Some(field_id) => { + fields_ids.insert(field_id); + }, + None => return Err(FieldIdMapMissingEntry::FieldName { + field_name: name, + process: "Index::filterable_fields_ids", + }.into()), + } + } + + Ok(fields_ids) } /* faceted documents ids */ @@ -393,7 +410,7 @@ impl Index { /// Returns the faceted fields names. /// /// Faceted fields are the union of all the filterable, distinct, and Asc/Desc fields. - pub fn faceted_fields(&self, rtxn: &RoTxn) -> heed::Result> { + pub fn faceted_fields(&self, rtxn: &RoTxn) -> Result> { let filterable_fields = self.filterable_fields(rtxn)?; let distinct_field = self.distinct_field(rtxn)?; let asc_desc_fields = self.criteria(rtxn)? @@ -412,21 +429,25 @@ impl Index { Ok(faceted_fields) } - /// Same as `faceted_fields`, but returns ids instead. - pub fn faceted_fields_ids(&self, rtxn: &RoTxn) -> heed::Result> { - let faceted_fields = self.faceted_fields(rtxn)?; + /// Identical to `faceted_fields`, but returns ids instead. + pub fn faceted_fields_ids(&self, rtxn: &RoTxn) -> Result> { + let fields = self.faceted_fields(rtxn)?; let fields_ids_map = self.fields_ids_map(rtxn)?; - let faceted_fields = faceted_fields - .iter() - .map(|k| { - fields_ids_map - .id(k) - .ok_or_else(|| format!("{:?} should be present in the field id map", k)) - .expect("corrupted data: ") - }) - .collect(); - Ok(faceted_fields) + let mut fields_ids = HashSet::new(); + for name in fields.into_iter() { + match fields_ids_map.id(&name) { + Some(field_id) => { + fields_ids.insert(field_id); + }, + None => return Err(FieldIdMapMissingEntry::FieldName { + field_name: name, + process: "Index::faceted_fields_ids", + }.into()), + } + } + + Ok(fields_ids) } /* faceted documents ids */ @@ -651,19 +672,23 @@ impl Index { } /// Returns the index creation time. - pub fn created_at(&self, rtxn: &RoTxn) -> heed::Result> { - let time = self.main + pub fn created_at(&self, rtxn: &RoTxn) -> Result> { + Ok(self.main .get::<_, Str, SerdeJson>>(rtxn, main_key::CREATED_AT_KEY)? - .expect("Index without creation time"); - Ok(time) + .ok_or(InternalError::DatabaseMissingEntry { + db_name: db_name::MAIN, + key: Some(main_key::CREATED_AT_KEY), + })?) } /// Returns the index last updated time. - pub fn updated_at(&self, rtxn: &RoTxn) -> heed::Result> { - let time = self.main + pub fn updated_at(&self, rtxn: &RoTxn) -> Result> { + Ok(self.main .get::<_, Str, SerdeJson>>(rtxn, main_key::UPDATED_AT_KEY)? - .expect("Index without update time"); - Ok(time) + .ok_or(InternalError::DatabaseMissingEntry { + db_name: db_name::MAIN, + key: Some(main_key::UPDATED_AT_KEY), + })?) } pub(crate) fn set_updated_at(&self, wtxn: &mut RwTxn, time: &DateTime) -> heed::Result<()> { diff --git a/milli/src/search/criteria/mod.rs b/milli/src/search/criteria/mod.rs index 981fc3ef2..48af0b8aa 100644 --- a/milli/src/search/criteria/mod.rs +++ b/milli/src/search/criteria/mod.rs @@ -76,7 +76,7 @@ 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) -> Result>; fn field_id_word_count_docids(&self, field_id: FieldId, word_count: u8) -> heed::Result>; fn word_level_position_docids(&self, word: &str, level: TreeLevel, left: u32, right: u32) -> heed::Result>; } @@ -174,7 +174,7 @@ 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) -> 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()), @@ -478,7 +478,7 @@ pub mod test { todo!() } - fn searchable_fields_ids(&self) -> heed::Result> { + fn searchable_fields_ids(&self) -> Result> { todo!() } diff --git a/milli/src/search/distinct/facet_distinct.rs b/milli/src/search/distinct/facet_distinct.rs index f86d6b8ed..b9ffd9d90 100644 --- a/milli/src/search/distinct/facet_distinct.rs +++ b/milli/src/search/distinct/facet_distinct.rs @@ -3,9 +3,11 @@ use std::mem::size_of; use heed::types::ByteSlice; use roaring::RoaringBitmap; -use super::{Distinct, DocIter}; +use crate::error::InternalError; use crate::heed_codec::facet::*; +use crate::index::db_name; use crate::{DocumentId, FieldId, Index, Result}; +use super::{Distinct, DocIter}; const FID_SIZE: usize = size_of::(); const DOCID_SIZE: usize = size_of::(); @@ -64,7 +66,10 @@ impl<'a> FacetDistinctIter<'a> { let ((_, _, value), _) = item?; let facet_docids = self .facet_string_docids(value)? - .expect("Corrupted data: Facet values must exist"); + .ok_or(InternalError::DatabaseMissingEntry { + db_name: db_name::FACET_ID_STRING_DOCIDS, + key: None, + })?; self.excluded.union_with(&facet_docids); } @@ -80,7 +85,10 @@ impl<'a> FacetDistinctIter<'a> { let ((_, _, value), _) = item?; let facet_docids = self .facet_number_docids(value)? - .expect("Corrupted data: Facet values must exist"); + .ok_or(InternalError::DatabaseMissingEntry { + db_name: db_name::FACET_ID_F64_DOCIDS, + key: None, + })?; self.excluded.union_with(&facet_docids); } diff --git a/milli/src/search/mod.rs b/milli/src/search/mod.rs index f8c7b5d9b..9deb541e3 100644 --- a/milli/src/search/mod.rs +++ b/milli/src/search/mod.rs @@ -13,7 +13,7 @@ use meilisearch_tokenizer::{Analyzer, AnalyzerConfig}; use once_cell::sync::Lazy; use roaring::bitmap::RoaringBitmap; -use distinct::{Distinct, DocIter, FacetDistinct, NoopDistinct}; +use crate::error::FieldIdMapMissingEntry; use crate::search::criteria::r#final::{Final, FinalResult}; use crate::{Index, DocumentId, Result}; @@ -22,6 +22,8 @@ pub use self::matching_words::MatchingWords; pub(crate) use self::facet::ParserRule; use self::query_tree::QueryTreeBuilder; +use distinct::{Distinct, DocIter, FacetDistinct, NoopDistinct}; + // Building these factories is not free. static LEVDIST0: Lazy = Lazy::new(|| LevBuilder::new(0, true)); static LEVDIST1: Lazy = Lazy::new(|| LevBuilder::new(1, true)); @@ -142,7 +144,10 @@ impl<'a> Search<'a> { None => self.perform_sort(NoopDistinct, matching_words, criteria), Some(name) => { let field_ids_map = self.index.fields_ids_map(self.rtxn)?; - let id = field_ids_map.id(name).expect("distinct not present in field map"); + let id = field_ids_map.id(name).ok_or_else(|| FieldIdMapMissingEntry::FieldName { + field_name: name.to_string(), + process: "fetching distint attribute", + })?; let distinct = FacetDistinct::new(id, self.index, self.rtxn); self.perform_sort(distinct, matching_words, criteria) } diff --git a/milli/src/update/delete_documents.rs b/milli/src/update/delete_documents.rs index ceba7bf01..7fc7e5d77 100644 --- a/milli/src/update/delete_documents.rs +++ b/milli/src/update/delete_documents.rs @@ -7,7 +7,7 @@ use heed::types::{ByteSlice, Unit}; use roaring::RoaringBitmap; use serde_json::Value; -use crate::error::{InternalError, UserError}; +use crate::error::{InternalError, FieldIdMapMissingEntry, UserError}; use crate::heed_codec::CboRoaringBitmapCodec; use crate::index::{db_name, main_key}; use crate::{Index, DocumentId, FieldId, BEU32, SmallString32, ExternalDocumentsIds, Result}; @@ -84,7 +84,12 @@ impl<'t, 'u, 'i> DeleteDocuments<'t, 'u, 'i> { key: Some(main_key::PRIMARY_KEY_KEY), } })?; - let id_field = fields_ids_map.id(primary_key).expect(r#"the field "id" to be present"#); + let id_field = fields_ids_map.id(primary_key).ok_or_else(|| { + FieldIdMapMissingEntry::FieldName { + field_name: primary_key.to_string(), + process: "DeleteDocuments::execute", + } + })?; let Index { env: _env,