stops storing the whole fieldids weights map when no searchable are defined

This commit is contained in:
Tamo 2024-05-15 17:16:10 +02:00
parent 7ec4e2a3fb
commit ad4d8502b3
3 changed files with 56 additions and 29 deletions

View File

@ -4,7 +4,7 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{FieldId, Weight}; use crate::{FieldId, FieldsIdsMap, Weight};
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
pub struct FieldidsWeightsMap { pub struct FieldidsWeightsMap {
@ -19,6 +19,13 @@ impl FieldidsWeightsMap {
self.map.insert(fid, weight) self.map.insert(fid, weight)
} }
/// Create the map from the fields ids maps.
/// Should only be called in the case there are NO searchable attributes.
/// The weights and the fields ids will have the same values.
pub fn from_field_id_map_without_searchable(fid_map: &FieldsIdsMap) -> Self {
FieldidsWeightsMap { map: fid_map.ids().map(|fid| (fid, fid)).collect() }
}
/// Removes a field id from the map, returning the associated weight previously in the map. /// Removes a field id from the map, returning the associated weight previously in the map.
pub fn remove(&mut self, fid: FieldId) -> Option<Weight> { pub fn remove(&mut self, fid: FieldId) -> Option<Weight> {
self.map.remove(&fid) self.map.remove(&fid)

View File

@ -436,11 +436,20 @@ impl Index {
/// Get the fieldids weights map which associates the field ids to their weights /// Get the fieldids weights map which associates the field ids to their weights
pub fn fieldids_weights_map(&self, rtxn: &RoTxn) -> heed::Result<FieldidsWeightsMap> { pub fn fieldids_weights_map(&self, rtxn: &RoTxn) -> heed::Result<FieldidsWeightsMap> {
Ok(self self.main
.main
.remap_types::<Str, SerdeJson<_>>() .remap_types::<Str, SerdeJson<_>>()
.get(rtxn, main_key::FIELDIDS_WEIGHTS_MAP_KEY)? .get(rtxn, main_key::FIELDIDS_WEIGHTS_MAP_KEY)?
.unwrap_or_default()) .map(Ok)
.unwrap_or_else(|| {
Ok(FieldidsWeightsMap::from_field_id_map_without_searchable(
&self.fields_ids_map(rtxn)?,
))
})
}
/// Delete the fieldsids weights map
pub fn delete_fieldids_weights_map(&self, wtxn: &mut RwTxn) -> heed::Result<bool> {
self.main.remap_key_type::<Str>().delete(wtxn, main_key::FIELDIDS_WEIGHTS_MAP_KEY)
} }
pub fn searchable_fields_and_weights<'a>( pub fn searchable_fields_and_weights<'a>(
@ -629,29 +638,13 @@ impl Index {
pub(crate) fn put_all_searchable_fields_from_fields_ids_map( pub(crate) fn put_all_searchable_fields_from_fields_ids_map(
&self, &self,
wtxn: &mut RwTxn, wtxn: &mut RwTxn,
user_fields: Option<&[&str]>, user_fields: &[&str],
fields_ids_map: &FieldsIdsMap, fields_ids_map: &FieldsIdsMap,
) -> Result<()> { ) -> Result<()> {
// Special case if there is no user defined fields.
// Then the whole field id map is marked as searchable.
if user_fields.is_none() {
let mut weights = self.fieldids_weights_map(wtxn)?;
let mut searchable = Vec::new();
for (weight, (fid, name)) in fields_ids_map.iter().enumerate() {
searchable.push(name);
weights.insert(fid, weight as u16);
}
self.put_searchable_fields(wtxn, &searchable)?;
self.put_fieldids_weights_map(wtxn, &weights)?;
return Ok(());
}
let user_fields = user_fields.unwrap();
// We can write the user defined searchable fields as-is. // We can write the user defined searchable fields as-is.
self.put_user_defined_searchable_fields(wtxn, user_fields)?; self.put_user_defined_searchable_fields(wtxn, user_fields)?;
let mut weights = self.fieldids_weights_map(wtxn)?; let mut weights = FieldidsWeightsMap::default();
// Now we generate the real searchable fields: // Now we generate the real searchable fields:
// 1. Take the user defined searchable fields as-is to keep the priority defined by the attributes criterion. // 1. Take the user defined searchable fields as-is to keep the priority defined by the attributes criterion.
@ -682,6 +675,7 @@ impl Index {
pub(crate) fn delete_all_searchable_fields(&self, wtxn: &mut RwTxn) -> heed::Result<bool> { pub(crate) fn delete_all_searchable_fields(&self, wtxn: &mut RwTxn) -> heed::Result<bool> {
let did_delete_searchable = self.delete_searchable_fields(wtxn)?; let did_delete_searchable = self.delete_searchable_fields(wtxn)?;
let did_delete_user_defined = self.delete_user_defined_searchable_fields(wtxn)?; let did_delete_user_defined = self.delete_user_defined_searchable_fields(wtxn)?;
self.delete_fieldids_weights_map(wtxn)?;
Ok(did_delete_searchable || did_delete_user_defined) Ok(did_delete_searchable || did_delete_user_defined)
} }

View File

@ -490,7 +490,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
self.index.put_all_searchable_fields_from_fields_ids_map( self.index.put_all_searchable_fields_from_fields_ids_map(
self.wtxn, self.wtxn,
Some(&names), &names,
&fields_ids_map, &fields_ids_map,
)?; )?;
self.index.put_fields_ids_map(self.wtxn, &fields_ids_map)?; self.index.put_fields_ids_map(self.wtxn, &fields_ids_map)?;
@ -1228,11 +1228,13 @@ impl InnerIndexSettings {
.map(|searchable| searchable.iter().map(|s| s.as_str()).collect::<Vec<_>>()); .map(|searchable| searchable.iter().map(|s| s.as_str()).collect::<Vec<_>>());
// in case new fields were introduced we're going to recreate the searchable fields. // in case new fields were introduced we're going to recreate the searchable fields.
if let Some(searchable_fields) = searchable_fields {
index.put_all_searchable_fields_from_fields_ids_map( index.put_all_searchable_fields_from_fields_ids_map(
wtxn, wtxn,
searchable_fields.as_deref(), &searchable_fields,
&self.fields_ids_map, &self.fields_ids_map,
)?; )?;
}
let searchable_fields_ids = index.searchable_fields_ids(wtxn)?; let searchable_fields_ids = index.searchable_fields_ids(wtxn)?;
self.searchable_fields_ids = searchable_fields_ids; self.searchable_fields_ids = searchable_fields_ids;
@ -1513,7 +1515,7 @@ mod tests {
use crate::error::Error; use crate::error::Error;
use crate::index::tests::TempIndex; use crate::index::tests::TempIndex;
use crate::update::ClearDocuments; use crate::update::ClearDocuments;
use crate::{Criterion, Filter, SearchResult}; use crate::{db_snap, Criterion, Filter, SearchResult};
#[test] #[test]
fn set_and_reset_searchable_fields() { fn set_and_reset_searchable_fields() {
@ -1542,6 +1544,17 @@ mod tests {
wtxn.commit().unwrap(); wtxn.commit().unwrap();
db_snap!(index, fields_ids_map, @r###"
0 id |
1 name |
2 age |
"###);
db_snap!(index, searchable_fields, @r###"["name"]"###);
db_snap!(index, fieldids_weights_map, @r###"
fid weight
1 0 |
"###);
// Check that the searchable field is correctly set to "name" only. // Check that the searchable field is correctly set to "name" only.
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
// When we search for something that is not in // When we search for something that is not in
@ -1565,6 +1578,19 @@ mod tests {
}) })
.unwrap(); .unwrap();
db_snap!(index, fields_ids_map, @r###"
0 id |
1 name |
2 age |
"###);
db_snap!(index, searchable_fields, @r###"["id", "name", "age"]"###);
db_snap!(index, fieldids_weights_map, @r###"
fid weight
0 0 |
1 1 |
2 2 |
"###);
// Check that the searchable field have been reset and documents are found now. // Check that the searchable field have been reset and documents are found now.
let rtxn = index.read_txn().unwrap(); let rtxn = index.read_txn().unwrap();
let fid_map = index.fields_ids_map(&rtxn).unwrap(); let fid_map = index.fields_ids_map(&rtxn).unwrap();