Introduce the faceted fields setting

This commit is contained in:
Clément Renault 2020-11-11 17:08:18 +01:00
parent 72f18759ba
commit ebe7087bff
No known key found for this signature in database
GPG Key ID: 92ADA4E935E71FA4

View File

@ -1,3 +1,5 @@
use std::collections::HashMap;
use anyhow::Context; use anyhow::Context;
use grenad::CompressionType; use grenad::CompressionType;
use rayon::ThreadPool; use rayon::ThreadPool;
@ -22,6 +24,7 @@ pub struct Settings<'a, 't, 'u, 'i> {
// however if it is `Some(None)` it means that the user forced a reset of the setting. // however if it is `Some(None)` it means that the user forced a reset of the setting.
searchable_fields: Option<Option<Vec<String>>>, searchable_fields: Option<Option<Vec<String>>>,
displayed_fields: Option<Option<Vec<String>>>, displayed_fields: Option<Option<Vec<String>>>,
faceted_fields: Option<Vec<String>>,
} }
impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> { impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
@ -39,6 +42,7 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
thread_pool: None, thread_pool: None,
searchable_fields: None, searchable_fields: None,
displayed_fields: None, displayed_fields: None,
faceted_fields: None,
} }
} }
@ -58,13 +62,77 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
self.displayed_fields = Some(Some(names)); self.displayed_fields = Some(Some(names));
} }
pub fn set_faceted_fields(&mut self, names: Vec<String>) {
self.faceted_fields = Some(names);
}
pub fn execute<F>(self, progress_callback: F) -> anyhow::Result<()> pub fn execute<F>(self, progress_callback: F) -> anyhow::Result<()>
where where
F: Fn(UpdateIndexingStep) + Sync F: Fn(UpdateIndexingStep) + Sync
{ {
if let Some(fields_names) = self.faceted_fields {
let current_faceted_fields = self.index.faceted_fields(self.wtxn)?;
let current_fields_ids_map = self.index.fields_ids_map(self.wtxn)?;
let mut fields_ids_map = current_fields_ids_map.clone();
let mut faceted_fields = HashMap::new();
for name in fields_names {
let id = fields_ids_map.insert(&name).context("field id limit reached")?;
match current_faceted_fields.get(&id) {
Some(ftype) => faceted_fields.insert(id, ftype.clone()),
None => faceted_fields.insert(id, None),
};
}
let transform = Transform {
rtxn: &self.wtxn,
index: self.index,
log_every_n: self.log_every_n,
chunk_compression_type: self.chunk_compression_type,
chunk_compression_level: self.chunk_compression_level,
chunk_fusing_shrink_size: self.chunk_fusing_shrink_size,
max_nb_chunks: self.max_nb_chunks,
max_memory: self.max_memory,
index_documents_method: IndexDocumentsMethod::ReplaceDocuments,
autogenerate_docids: false,
};
// We compute or generate the new primary key field id.
let primary_key = match self.index.primary_key(&self.wtxn)? {
Some(id) => {
let name = current_fields_ids_map.name(id).unwrap();
fields_ids_map.insert(name).context("field id limit reached")?
},
None => fields_ids_map.insert("id").context("field id limit reached")?,
};
// We remap the documents fields based on the new `FieldsIdsMap`.
let output = transform.remap_index_documents(primary_key, fields_ids_map.clone())?;
// We write the faceted_fields fields into the database here.
self.index.put_faceted_fields(self.wtxn, &faceted_fields)?;
// We clear the full database (words-fst, documents ids and documents content).
ClearDocuments::new(self.wtxn, self.index).execute()?;
// We index the generated `TransformOutput` which must contain
// all the documents with fields in the newly defined searchable order.
let mut indexing_builder = IndexDocuments::new(self.wtxn, self.index);
indexing_builder.log_every_n = self.log_every_n;
indexing_builder.max_nb_chunks = self.max_nb_chunks;
indexing_builder.max_memory = self.max_memory;
indexing_builder.linked_hash_map_size = self.linked_hash_map_size;
indexing_builder.chunk_compression_type = self.chunk_compression_type;
indexing_builder.chunk_compression_level = self.chunk_compression_level;
indexing_builder.chunk_fusing_shrink_size = self.chunk_fusing_shrink_size;
indexing_builder.thread_pool = self.thread_pool;
indexing_builder.execute_raw(output, &progress_callback)?;
}
// Check that the searchable attributes have been specified. // Check that the searchable attributes have been specified.
if let Some(value) = self.searchable_fields { if let Some(value) = self.searchable_fields {
let current_displayed_fields = self.index.displayed_fields(self.wtxn)?; let current_displayed_fields = self.index.displayed_fields(self.wtxn)?;
let current_faceted_fields = self.index.faceted_fields(self.wtxn)?;
let current_fields_ids_map = self.index.fields_ids_map(self.wtxn)?; let current_fields_ids_map = self.index.fields_ids_map(self.wtxn)?;
let result = match value { let result = match value {
@ -82,6 +150,7 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
fields_ids_map, fields_ids_map,
Some(searchable_fields), Some(searchable_fields),
current_displayed_fields.map(ToOwned::to_owned), current_displayed_fields.map(ToOwned::to_owned),
current_faceted_fields,
) )
} else { } else {
// We create or generate the fields ids corresponding to those names. // We create or generate the fields ids corresponding to those names.
@ -97,7 +166,7 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
fields_ids_map.insert(name).context("field id limit reached")?; fields_ids_map.insert(name).context("field id limit reached")?;
} }
// We must also update the displayed fields according to the new `FieldsIdsMap`. // We must update the displayed fields according to the new `FieldsIdsMap`.
let displayed_fields = match current_displayed_fields { let displayed_fields = match current_displayed_fields {
Some(fields) => { Some(fields) => {
let mut displayed_fields = Vec::new(); let mut displayed_fields = Vec::new();
@ -111,17 +180,26 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
None => None, None => None,
}; };
(fields_ids_map, Some(searchable_fields), displayed_fields) // We must update the faceted fields according to the new `FieldsIdsMap`.
let mut faceted_fields = HashMap::new();
for (id, ftype) in current_faceted_fields {
let name = current_fields_ids_map.name(id).unwrap();
let id = fields_ids_map.id(name).context("field id limit reached")?;
faceted_fields.insert(id, ftype);
}
(fields_ids_map, Some(searchable_fields), displayed_fields, faceted_fields)
} }
}, },
None => ( None => (
current_fields_ids_map.clone(), current_fields_ids_map.clone(),
None, None,
current_displayed_fields.map(ToOwned::to_owned), current_displayed_fields.map(ToOwned::to_owned),
current_faceted_fields,
), ),
}; };
let (mut fields_ids_map, searchable_fields, displayed_fields) = result; let (mut fields_ids_map, searchable_fields, displayed_fields, faceted_fields) = result;
let transform = Transform { let transform = Transform {
rtxn: &self.wtxn, rtxn: &self.wtxn,
@ -166,6 +244,9 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
None => self.index.delete_displayed_fields(self.wtxn).map(drop)?, None => self.index.delete_displayed_fields(self.wtxn).map(drop)?,
} }
// We write the faceted_fields fields into the database here.
self.index.put_faceted_fields(self.wtxn, &faceted_fields)?;
// We clear the full database (words-fst, documents ids and documents content). // We clear the full database (words-fst, documents ids and documents content).
ClearDocuments::new(self.wtxn, self.index).execute()?; ClearDocuments::new(self.wtxn, self.index).execute()?;
@ -180,7 +261,7 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
indexing_builder.chunk_compression_level = self.chunk_compression_level; indexing_builder.chunk_compression_level = self.chunk_compression_level;
indexing_builder.chunk_fusing_shrink_size = self.chunk_fusing_shrink_size; indexing_builder.chunk_fusing_shrink_size = self.chunk_fusing_shrink_size;
indexing_builder.thread_pool = self.thread_pool; indexing_builder.thread_pool = self.thread_pool;
indexing_builder.execute_raw(output, progress_callback)?; indexing_builder.execute_raw(output, &progress_callback)?;
} }
// Check that the displayed attributes have been specified. // Check that the displayed attributes have been specified.