diff --git a/milli/src/index.rs b/milli/src/index.rs index c66222ab1..d0d148d86 100644 --- a/milli/src/index.rs +++ b/milli/src/index.rs @@ -2662,17 +2662,18 @@ pub(crate) mod tests { settings.set_filterable_fields(HashSet::from([S("age")])); }) .unwrap(); + // The order of the field id map shouldn't change db_snap!(index, fields_ids_map, @r###" 0 name | - 1 realName | - 2 id | - 3 age | + 1 id | + 2 age | + 3 realName | "###); db_snap!(index, searchable_fields, @r###"["name", "realName"]"###); db_snap!(index, fieldids_weights_map, @r###" fid weight 0 0 | - 1 1 | + 3 1 | "###); } } diff --git a/milli/src/update/settings.rs b/milli/src/update/settings.rs index 19b2c5778..6875e6f47 100644 --- a/milli/src/update/settings.rs +++ b/milli/src/update/settings.rs @@ -12,6 +12,7 @@ use time::OffsetDateTime; use super::index_documents::{IndexDocumentsConfig, Transform}; use super::IndexerConfig; use crate::criterion::Criterion; +use crate::documents::FieldIdMapper; use crate::error::UserError; use crate::index::{DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS}; use crate::order_by_map::OrderByMap; @@ -461,8 +462,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { Ok(true) } - /// Updates the index's searchable attributes. This causes the field map to be recomputed to - /// reflect the order of the searchable attributes. + /// Updates the index's searchable attributes. fn update_searchable(&mut self) -> Result { match self.searchable_fields { Setting::Set(ref fields) => { @@ -480,17 +480,20 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> { // ids for any settings that uses the facets. (distinct_fields, filterable_fields). let old_fields_ids_map = self.index.fields_ids_map(self.wtxn)?; - let mut new_fields_ids_map = FieldsIdsMap::new(); - // fields are deduplicated, only the first occurrence is taken into account - let names = fields.iter().unique().map(String::as_str).collect::>(); + // Since we're updating the settings we can only add new fields at the end of the field id map + let mut new_fields_ids_map = old_fields_ids_map.clone(); + let names = fields + .iter() + // fields are deduplicated, only the first occurrence is taken into account + .unique() + .map(String::as_str) + .collect::>(); // Add all the searchable attributes to the field map, and then add the // remaining fields from the old field map to the new one for name in names.iter() { - new_fields_ids_map.insert(name).ok_or(UserError::AttributeLimitReached)?; - } - - for (_, name) in old_fields_ids_map.iter() { + // The fields ids map won't change the field id of already present elements thus only the + // new fields will be inserted. new_fields_ids_map.insert(name).ok_or(UserError::AttributeLimitReached)?; }