mirror of
https://github.com/meilisearch/MeiliSearch
synced 2025-07-04 04:17:10 +02:00
Support indexingFragments
and searchFragments
in settings
This commit is contained in:
parent
f3d5c74c02
commit
41620d5325
2 changed files with 213 additions and 105 deletions
|
@ -9,10 +9,11 @@ use std::str::FromStr;
|
||||||
use deserr::{DeserializeError, Deserr, ErrorKind, MergeWithError, ValuePointerRef};
|
use deserr::{DeserializeError, Deserr, ErrorKind, MergeWithError, ValuePointerRef};
|
||||||
use fst::IntoStreamer;
|
use fst::IntoStreamer;
|
||||||
use milli::disabled_typos_terms::DisabledTyposTerms;
|
use milli::disabled_typos_terms::DisabledTyposTerms;
|
||||||
use milli::index::{IndexEmbeddingConfig, PrefixSearch};
|
use milli::index::PrefixSearch;
|
||||||
use milli::proximity::ProximityPrecision;
|
use milli::proximity::ProximityPrecision;
|
||||||
pub use milli::update::ChatSettings;
|
pub use milli::update::ChatSettings;
|
||||||
use milli::update::Setting;
|
use milli::update::Setting;
|
||||||
|
use milli::vector::db::IndexEmbeddingConfig;
|
||||||
use milli::{Criterion, CriterionError, FilterableAttributesRule, Index, DEFAULT_VALUES_PER_FACET};
|
use milli::{Criterion, CriterionError, FilterableAttributesRule, Index, DEFAULT_VALUES_PER_FACET};
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
@ -911,6 +912,7 @@ pub fn settings(
|
||||||
};
|
};
|
||||||
|
|
||||||
let embedders: BTreeMap<_, _> = index
|
let embedders: BTreeMap<_, _> = index
|
||||||
|
.embedding_configs()
|
||||||
.embedding_configs(rtxn)?
|
.embedding_configs(rtxn)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|IndexEmbeddingConfig { name, config, .. }| {
|
.map(|IndexEmbeddingConfig { name, config, .. }| {
|
||||||
|
|
|
@ -7,7 +7,6 @@ use std::sync::Arc;
|
||||||
use charabia::{Normalize, Tokenizer, TokenizerBuilder};
|
use charabia::{Normalize, Tokenizer, TokenizerBuilder};
|
||||||
use deserr::{DeserializeError, Deserr};
|
use deserr::{DeserializeError, Deserr};
|
||||||
use itertools::{merge_join_by, EitherOrBoth, Itertools};
|
use itertools::{merge_join_by, EitherOrBoth, Itertools};
|
||||||
use roaring::RoaringBitmap;
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
|
@ -23,22 +22,25 @@ use crate::error::UserError::{self, InvalidChatSettingsDocumentTemplateMaxBytes}
|
||||||
use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder};
|
use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, MetadataBuilder};
|
||||||
use crate::filterable_attributes_rules::match_faceted_field;
|
use crate::filterable_attributes_rules::match_faceted_field;
|
||||||
use crate::index::{
|
use crate::index::{
|
||||||
ChatConfig, IndexEmbeddingConfig, PrefixSearch, SearchParameters,
|
ChatConfig, PrefixSearch, SearchParameters, DEFAULT_MIN_WORD_LEN_ONE_TYPO,
|
||||||
DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS,
|
DEFAULT_MIN_WORD_LEN_TWO_TYPOS,
|
||||||
};
|
};
|
||||||
use crate::order_by_map::OrderByMap;
|
use crate::order_by_map::OrderByMap;
|
||||||
use crate::progress::EmbedderStats;
|
use crate::progress::{EmbedderStats, Progress};
|
||||||
use crate::progress::Progress;
|
|
||||||
use crate::prompt::{default_max_bytes, default_template_text, PromptData};
|
use crate::prompt::{default_max_bytes, default_template_text, PromptData};
|
||||||
use crate::proximity::ProximityPrecision;
|
use crate::proximity::ProximityPrecision;
|
||||||
use crate::update::index_documents::IndexDocumentsMethod;
|
use crate::update::index_documents::IndexDocumentsMethod;
|
||||||
use crate::update::new::indexer::reindex;
|
use crate::update::new::indexer::reindex;
|
||||||
use crate::update::{IndexDocuments, UpdateIndexingStep};
|
use crate::update::{IndexDocuments, UpdateIndexingStep};
|
||||||
|
use crate::vector::db::{FragmentConfigs, IndexEmbeddingConfig};
|
||||||
|
use crate::vector::json_template::JsonTemplate;
|
||||||
use crate::vector::settings::{
|
use crate::vector::settings::{
|
||||||
EmbedderAction, EmbedderSource, EmbeddingSettings, NestingContext, ReindexAction,
|
EmbedderAction, EmbedderSource, EmbeddingSettings, NestingContext, ReindexAction,
|
||||||
SubEmbeddingSettings, WriteBackToDocuments,
|
SubEmbeddingSettings, WriteBackToDocuments,
|
||||||
};
|
};
|
||||||
use crate::vector::{Embedder, EmbeddingConfig, EmbeddingConfigs};
|
use crate::vector::{
|
||||||
|
Embedder, EmbeddingConfig, RuntimeEmbedder, RuntimeEmbedders, RuntimeFragment,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
ChannelCongestion, FieldId, FilterableAttributesRule, Index, LocalizedAttributesRule, Result,
|
ChannelCongestion, FieldId, FilterableAttributesRule, Index, LocalizedAttributesRule, Result,
|
||||||
};
|
};
|
||||||
|
@ -1044,22 +1046,27 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||||
match std::mem::take(&mut self.embedder_settings) {
|
match std::mem::take(&mut self.embedder_settings) {
|
||||||
Setting::Set(configs) => self.update_embedding_configs_set(configs),
|
Setting::Set(configs) => self.update_embedding_configs_set(configs),
|
||||||
Setting::Reset => {
|
Setting::Reset => {
|
||||||
|
let embedders = self.index.embedding_configs();
|
||||||
// all vectors should be written back to documents
|
// all vectors should be written back to documents
|
||||||
let old_configs = self.index.embedding_configs(self.wtxn)?;
|
let old_configs = embedders.embedding_configs(self.wtxn)?;
|
||||||
let remove_all: Result<BTreeMap<String, EmbedderAction>> = old_configs
|
let remove_all: Result<BTreeMap<String, EmbedderAction>> = old_configs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|IndexEmbeddingConfig { name, config, user_provided }| -> Result<_> {
|
.map(|IndexEmbeddingConfig { name, config, fragments: _ }| -> Result<_> {
|
||||||
let embedder_id =
|
let embedder_info = embedders.embedder_info(self.wtxn, &name)?.ok_or(
|
||||||
self.index.embedder_category_id.get(self.wtxn, &name)?.ok_or(
|
crate::InternalError::DatabaseMissingEntry {
|
||||||
crate::InternalError::DatabaseMissingEntry {
|
db_name: crate::index::db_name::VECTOR_EMBEDDER_CATEGORY_ID,
|
||||||
db_name: crate::index::db_name::VECTOR_EMBEDDER_CATEGORY_ID,
|
key: None,
|
||||||
key: None,
|
},
|
||||||
},
|
)?;
|
||||||
)?;
|
|
||||||
Ok((
|
Ok((
|
||||||
name,
|
name,
|
||||||
EmbedderAction::with_write_back(
|
EmbedderAction::with_write_back(
|
||||||
WriteBackToDocuments { embedder_id, user_provided },
|
WriteBackToDocuments {
|
||||||
|
embedder_id: embedder_info.embedder_id,
|
||||||
|
user_provided: embedder_info
|
||||||
|
.embedding_status
|
||||||
|
.into_user_provided(),
|
||||||
|
},
|
||||||
config.quantized(),
|
config.quantized(),
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
@ -1069,7 +1076,7 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||||
let remove_all = remove_all?;
|
let remove_all = remove_all?;
|
||||||
|
|
||||||
self.index.embedder_category_id.clear(self.wtxn)?;
|
self.index.embedder_category_id.clear(self.wtxn)?;
|
||||||
self.index.delete_embedding_configs(self.wtxn)?;
|
embedders.delete_embedding_configs(self.wtxn)?;
|
||||||
Ok(remove_all)
|
Ok(remove_all)
|
||||||
}
|
}
|
||||||
Setting::NotSet => Ok(Default::default()),
|
Setting::NotSet => Ok(Default::default()),
|
||||||
|
@ -1081,12 +1088,12 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||||
configs: BTreeMap<String, Setting<EmbeddingSettings>>,
|
configs: BTreeMap<String, Setting<EmbeddingSettings>>,
|
||||||
) -> Result<BTreeMap<String, EmbedderAction>> {
|
) -> Result<BTreeMap<String, EmbedderAction>> {
|
||||||
use crate::vector::settings::SettingsDiff;
|
use crate::vector::settings::SettingsDiff;
|
||||||
|
let embedders = self.index.embedding_configs();
|
||||||
let old_configs = self.index.embedding_configs(self.wtxn)?;
|
let old_configs = embedders.embedding_configs(self.wtxn)?;
|
||||||
let old_configs: BTreeMap<String, (EmbeddingSettings, RoaringBitmap)> = old_configs
|
let old_configs: BTreeMap<String, (EmbeddingSettings, FragmentConfigs)> = old_configs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|IndexEmbeddingConfig { name, config, user_provided }| {
|
.map(|IndexEmbeddingConfig { name, config, fragments }| {
|
||||||
(name, (config.into(), user_provided))
|
(name, (config.into(), fragments))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let mut updated_configs = BTreeMap::new();
|
let mut updated_configs = BTreeMap::new();
|
||||||
|
@ -1097,55 +1104,88 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||||
{
|
{
|
||||||
match joined {
|
match joined {
|
||||||
// updated config
|
// updated config
|
||||||
EitherOrBoth::Both((name, (old, user_provided)), (_, new)) => {
|
EitherOrBoth::Both((name, (old, mut fragments)), (_, new)) => {
|
||||||
let was_quantized = old.binary_quantized.set().unwrap_or_default();
|
let was_quantized = old.binary_quantized.set().unwrap_or_default();
|
||||||
let settings_diff = SettingsDiff::from_settings(&name, old, new)?;
|
let settings_diff = SettingsDiff::from_settings(&name, old, new)?;
|
||||||
match settings_diff {
|
match settings_diff {
|
||||||
SettingsDiff::Remove => {
|
SettingsDiff::Remove => {
|
||||||
|
let info = embedders.remove_embedder(self.wtxn, &name)?.ok_or(
|
||||||
|
crate::InternalError::DatabaseMissingEntry {
|
||||||
|
db_name: crate::index::db_name::VECTOR_EMBEDDER_CATEGORY_ID,
|
||||||
|
key: None,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
embedder = name,
|
embedder = name,
|
||||||
user_provided = user_provided.len(),
|
user_provided = info.embedding_status.user_provided_docids().len(),
|
||||||
"removing embedder"
|
"removing embedder"
|
||||||
);
|
);
|
||||||
let embedder_id =
|
|
||||||
self.index.embedder_category_id.get(self.wtxn, &name)?.ok_or(
|
|
||||||
crate::InternalError::DatabaseMissingEntry {
|
|
||||||
db_name: crate::index::db_name::VECTOR_EMBEDDER_CATEGORY_ID,
|
|
||||||
key: None,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
// free id immediately
|
|
||||||
self.index.embedder_category_id.delete(self.wtxn, &name)?;
|
|
||||||
embedder_actions.insert(
|
embedder_actions.insert(
|
||||||
name,
|
name,
|
||||||
EmbedderAction::with_write_back(
|
EmbedderAction::with_write_back(
|
||||||
WriteBackToDocuments { embedder_id, user_provided },
|
WriteBackToDocuments {
|
||||||
|
embedder_id: info.embedder_id,
|
||||||
|
user_provided: info.embedding_status.into_user_provided(),
|
||||||
|
},
|
||||||
was_quantized,
|
was_quantized,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
SettingsDiff::Reindex { action, updated_settings, quantize } => {
|
SettingsDiff::Reindex { action, updated_settings, quantize } => {
|
||||||
tracing::debug!(
|
let mut remove_fragments = None;
|
||||||
embedder = name,
|
let updated_settings = Setting::Set(updated_settings);
|
||||||
user_provided = user_provided.len(),
|
if let ReindexAction::RegenerateFragments(regenerate_fragments) =
|
||||||
?action,
|
&action
|
||||||
"reindex embedder"
|
{
|
||||||
);
|
let it = regenerate_fragments
|
||||||
embedder_actions.insert(
|
.iter()
|
||||||
name.clone(),
|
.filter(|(_, action)| {
|
||||||
|
matches!(
|
||||||
|
action,
|
||||||
|
crate::vector::settings::RegenerateFragment::Remove
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|(name, _)| name.as_str());
|
||||||
|
|
||||||
|
remove_fragments = fragments.remove_fragments(it);
|
||||||
|
|
||||||
|
let it = regenerate_fragments
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, action)| {
|
||||||
|
matches!(
|
||||||
|
action,
|
||||||
|
crate::vector::settings::RegenerateFragment::Add
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|(name, _)| name.clone());
|
||||||
|
fragments.add_new_fragments(it)?;
|
||||||
|
} else {
|
||||||
|
// needs full reindex of fragments
|
||||||
|
fragments = FragmentConfigs::new();
|
||||||
|
fragments.add_new_fragments(
|
||||||
|
crate::vector::settings::fragments_from_settings(
|
||||||
|
&updated_settings,
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
tracing::debug!(embedder = name, ?action, "reindex embedder");
|
||||||
|
|
||||||
|
let embedder_action =
|
||||||
EmbedderAction::with_reindex(action, was_quantized)
|
EmbedderAction::with_reindex(action, was_quantized)
|
||||||
.with_is_being_quantized(quantize),
|
.with_is_being_quantized(quantize);
|
||||||
);
|
|
||||||
let new =
|
let embedder_action = if let Some(remove_fragments) = remove_fragments {
|
||||||
validate_embedding_settings(Setting::Set(updated_settings), &name)?;
|
embedder_action.with_remove_fragments(remove_fragments)
|
||||||
updated_configs.insert(name, (new, user_provided));
|
} else {
|
||||||
|
embedder_action
|
||||||
|
};
|
||||||
|
|
||||||
|
embedder_actions.insert(name.clone(), embedder_action);
|
||||||
|
let new = validate_embedding_settings(updated_settings, &name)?;
|
||||||
|
updated_configs.insert(name, (new, fragments));
|
||||||
}
|
}
|
||||||
SettingsDiff::UpdateWithoutReindex { updated_settings, quantize } => {
|
SettingsDiff::UpdateWithoutReindex { updated_settings, quantize } => {
|
||||||
tracing::debug!(
|
tracing::debug!(embedder = name, "update without reindex embedder");
|
||||||
embedder = name,
|
|
||||||
user_provided = user_provided.len(),
|
|
||||||
"update without reindex embedder"
|
|
||||||
);
|
|
||||||
let new =
|
let new =
|
||||||
validate_embedding_settings(Setting::Set(updated_settings), &name)?;
|
validate_embedding_settings(Setting::Set(updated_settings), &name)?;
|
||||||
if quantize {
|
if quantize {
|
||||||
|
@ -1154,14 +1194,14 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||||
EmbedderAction::default().with_is_being_quantized(true),
|
EmbedderAction::default().with_is_being_quantized(true),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
updated_configs.insert(name, (new, user_provided));
|
updated_configs.insert(name, (new, fragments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// unchanged config
|
// unchanged config
|
||||||
EitherOrBoth::Left((name, (setting, user_provided))) => {
|
EitherOrBoth::Left((name, (setting, fragments))) => {
|
||||||
tracing::debug!(embedder = name, "unchanged embedder");
|
tracing::debug!(embedder = name, "unchanged embedder");
|
||||||
updated_configs.insert(name, (Setting::Set(setting), user_provided));
|
updated_configs.insert(name, (Setting::Set(setting), fragments));
|
||||||
}
|
}
|
||||||
// new config
|
// new config
|
||||||
EitherOrBoth::Right((name, mut setting)) => {
|
EitherOrBoth::Right((name, mut setting)) => {
|
||||||
|
@ -1176,47 +1216,42 @@ impl<'a, 't, 'i> Settings<'a, 't, 'i> {
|
||||||
name.clone(),
|
name.clone(),
|
||||||
EmbedderAction::with_reindex(ReindexAction::FullReindex, false),
|
EmbedderAction::with_reindex(ReindexAction::FullReindex, false),
|
||||||
);
|
);
|
||||||
updated_configs.insert(name, (setting, RoaringBitmap::new()));
|
let mut fragments = FragmentConfigs::new();
|
||||||
|
fragments.add_new_fragments(
|
||||||
|
crate::vector::settings::fragments_from_settings(&setting),
|
||||||
|
)?;
|
||||||
|
updated_configs.insert(name, (setting, fragments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut free_indices: [bool; u8::MAX as usize] = [true; u8::MAX as usize];
|
embedders.add_new_embedders(
|
||||||
for res in self.index.embedder_category_id.iter(self.wtxn)? {
|
self.wtxn,
|
||||||
let (_name, id) = res?;
|
embedder_actions
|
||||||
free_indices[id as usize] = false;
|
.iter()
|
||||||
}
|
// ignore actions that are not possible for a new embedder, most critically deleted embedders
|
||||||
let mut free_indices = free_indices.iter_mut().enumerate();
|
.filter(|(_, action)| matches!(action.reindex(), Some(ReindexAction::FullReindex)))
|
||||||
let mut find_free_index =
|
.map(|(name, _)| name.as_str()),
|
||||||
move || free_indices.find(|(_, free)| **free).map(|(index, _)| index as u8);
|
updated_configs.len(),
|
||||||
for (name, action) in embedder_actions.iter() {
|
)?;
|
||||||
// ignore actions that are not possible for a new embedder
|
|
||||||
if matches!(action.reindex(), Some(ReindexAction::FullReindex))
|
|
||||||
&& self.index.embedder_category_id.get(self.wtxn, name)?.is_none()
|
|
||||||
{
|
|
||||||
let id =
|
|
||||||
find_free_index().ok_or(UserError::TooManyEmbedders(updated_configs.len()))?;
|
|
||||||
tracing::debug!(embedder = name, id, "assigning free id to new embedder");
|
|
||||||
self.index.embedder_category_id.put(self.wtxn, name, &id)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let updated_configs: Vec<IndexEmbeddingConfig> = updated_configs
|
let updated_configs: Vec<IndexEmbeddingConfig> = updated_configs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(name, (config, user_provided))| match config {
|
.filter_map(|(name, (config, fragments))| match config {
|
||||||
Setting::Set(config) => {
|
Setting::Set(config) => {
|
||||||
Some(IndexEmbeddingConfig { name, config: config.into(), user_provided })
|
Some(IndexEmbeddingConfig { name, config: config.into(), fragments })
|
||||||
}
|
}
|
||||||
Setting::Reset => None,
|
Setting::Reset => None,
|
||||||
Setting::NotSet => Some(IndexEmbeddingConfig {
|
Setting::NotSet => Some(IndexEmbeddingConfig {
|
||||||
name,
|
name,
|
||||||
config: EmbeddingSettings::default().into(),
|
config: EmbeddingSettings::default().into(),
|
||||||
user_provided,
|
fragments: Default::default(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if updated_configs.is_empty() {
|
if updated_configs.is_empty() {
|
||||||
self.index.delete_embedding_configs(self.wtxn)?;
|
embedders.delete_embedding_configs(self.wtxn)?;
|
||||||
} else {
|
} else {
|
||||||
self.index.put_embedding_configs(self.wtxn, updated_configs)?;
|
embedders.put_embedding_configs(self.wtxn, updated_configs)?;
|
||||||
}
|
}
|
||||||
Ok(embedder_actions)
|
Ok(embedder_actions)
|
||||||
}
|
}
|
||||||
|
@ -1611,13 +1646,13 @@ impl InnerIndexSettingsDiff {
|
||||||
|
|
||||||
// if the user-defined searchables changed, then we need to reindex prompts.
|
// if the user-defined searchables changed, then we need to reindex prompts.
|
||||||
if cache_user_defined_searchables {
|
if cache_user_defined_searchables {
|
||||||
for (embedder_name, (config, _, _quantized)) in
|
for (embedder_name, runtime) in new_settings.embedding_configs.inner_as_ref() {
|
||||||
new_settings.embedding_configs.inner_as_ref()
|
let was_quantized = old_settings
|
||||||
{
|
.embedding_configs
|
||||||
let was_quantized =
|
.get(embedder_name)
|
||||||
old_settings.embedding_configs.get(embedder_name).is_some_and(|conf| conf.2);
|
.is_some_and(|conf| conf.is_quantized);
|
||||||
// skip embedders that don't use document templates
|
// skip embedders that don't use document templates
|
||||||
if !config.uses_document_template() {
|
if !runtime.embedder.uses_document_template() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1630,13 +1665,31 @@ impl InnerIndexSettingsDiff {
|
||||||
was_quantized,
|
was_quantized,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
std::collections::btree_map::Entry::Occupied(entry) => {
|
std::collections::btree_map::Entry::Occupied(mut entry) => {
|
||||||
|
// future-proofing, make sure to destructure here so that any new field is taken into account in this case
|
||||||
|
// case in point: adding `remove_fragments` was detected.
|
||||||
let EmbedderAction {
|
let EmbedderAction {
|
||||||
was_quantized: _,
|
was_quantized: _,
|
||||||
is_being_quantized: _,
|
is_being_quantized: _,
|
||||||
write_back: _, // We are deleting this embedder, so no point in regeneration
|
write_back, // We are deleting this embedder, so no point in regeneration
|
||||||
reindex: _, // We are already fully reindexing
|
reindex,
|
||||||
} = entry.get();
|
remove_fragments: _,
|
||||||
|
} = entry.get_mut();
|
||||||
|
|
||||||
|
// fixup reindex to make sure we regenerate all fragments
|
||||||
|
*reindex = match reindex.take() {
|
||||||
|
Some(ReindexAction::RegenerateFragments(_)) => {
|
||||||
|
Some(ReindexAction::RegeneratePrompts)
|
||||||
|
}
|
||||||
|
Some(reindex) => Some(reindex), // We are at least regenerating prompts
|
||||||
|
None => {
|
||||||
|
if write_back.is_none() {
|
||||||
|
Some(ReindexAction::RegeneratePrompts) // quantization case
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1790,7 +1843,7 @@ pub(crate) struct InnerIndexSettings {
|
||||||
pub exact_attributes: HashSet<FieldId>,
|
pub exact_attributes: HashSet<FieldId>,
|
||||||
pub disabled_typos_terms: DisabledTyposTerms,
|
pub disabled_typos_terms: DisabledTyposTerms,
|
||||||
pub proximity_precision: ProximityPrecision,
|
pub proximity_precision: ProximityPrecision,
|
||||||
pub embedding_configs: EmbeddingConfigs,
|
pub embedding_configs: RuntimeEmbedders,
|
||||||
pub embedder_category_id: HashMap<String, u8>,
|
pub embedder_category_id: HashMap<String, u8>,
|
||||||
pub geo_fields_ids: Option<(FieldId, FieldId)>,
|
pub geo_fields_ids: Option<(FieldId, FieldId)>,
|
||||||
pub prefix_search: PrefixSearch,
|
pub prefix_search: PrefixSearch,
|
||||||
|
@ -1801,7 +1854,7 @@ impl InnerIndexSettings {
|
||||||
pub fn from_index(
|
pub fn from_index(
|
||||||
index: &Index,
|
index: &Index,
|
||||||
rtxn: &heed::RoTxn<'_>,
|
rtxn: &heed::RoTxn<'_>,
|
||||||
embedding_configs: Option<EmbeddingConfigs>,
|
embedding_configs: Option<RuntimeEmbedders>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let stop_words = index.stop_words(rtxn)?;
|
let stop_words = index.stop_words(rtxn)?;
|
||||||
let stop_words = stop_words.map(|sw| sw.map_data(Vec::from).unwrap());
|
let stop_words = stop_words.map(|sw| sw.map_data(Vec::from).unwrap());
|
||||||
|
@ -1812,7 +1865,7 @@ impl InnerIndexSettings {
|
||||||
let proximity_precision = index.proximity_precision(rtxn)?.unwrap_or_default();
|
let proximity_precision = index.proximity_precision(rtxn)?.unwrap_or_default();
|
||||||
let embedding_configs = match embedding_configs {
|
let embedding_configs = match embedding_configs {
|
||||||
Some(embedding_configs) => embedding_configs,
|
Some(embedding_configs) => embedding_configs,
|
||||||
None => embedders(index.embedding_configs(rtxn)?)?,
|
None => embedders(index.embedding_configs().embedding_configs(rtxn)?)?,
|
||||||
};
|
};
|
||||||
let embedder_category_id = index
|
let embedder_category_id = index
|
||||||
.embedder_category_id
|
.embedder_category_id
|
||||||
|
@ -1900,28 +1953,49 @@ impl InnerIndexSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn embedders(embedding_configs: Vec<IndexEmbeddingConfig>) -> Result<EmbeddingConfigs> {
|
fn embedders(embedding_configs: Vec<IndexEmbeddingConfig>) -> Result<RuntimeEmbedders> {
|
||||||
let res: Result<_> = embedding_configs
|
let res: Result<_> = embedding_configs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(
|
.map(
|
||||||
|IndexEmbeddingConfig {
|
|IndexEmbeddingConfig {
|
||||||
name,
|
name,
|
||||||
config: EmbeddingConfig { embedder_options, prompt, quantized },
|
config: EmbeddingConfig { embedder_options, prompt, quantized },
|
||||||
..
|
fragments,
|
||||||
}| {
|
}| {
|
||||||
let prompt = Arc::new(prompt.try_into().map_err(crate::Error::from)?);
|
let document_template = prompt.try_into().map_err(crate::Error::from)?;
|
||||||
|
|
||||||
let embedder = Arc::new(
|
let embedder =
|
||||||
// cache_cap: no cache needed for indexing purposes
|
// cache_cap: no cache needed for indexing purposes
|
||||||
Embedder::new(embedder_options.clone(), 0)
|
Arc::new(Embedder::new(embedder_options.clone(), 0)
|
||||||
.map_err(crate::vector::Error::from)
|
.map_err(crate::vector::Error::from)
|
||||||
.map_err(crate::Error::from)?,
|
.map_err(crate::Error::from)?);
|
||||||
);
|
|
||||||
Ok((name, (embedder, prompt, quantized.unwrap_or_default())))
|
let fragments = fragments
|
||||||
|
.into_inner()
|
||||||
|
.into_iter()
|
||||||
|
.map(|fragment| {
|
||||||
|
let template = JsonTemplate::new(
|
||||||
|
embedder_options.fragment(&fragment.name).unwrap().clone(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
RuntimeFragment { name: fragment.name, id: fragment.id, template }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
name,
|
||||||
|
Arc::new(RuntimeEmbedder {
|
||||||
|
embedder,
|
||||||
|
document_template,
|
||||||
|
fragments,
|
||||||
|
is_quantized: quantized.unwrap_or_default(),
|
||||||
|
}),
|
||||||
|
))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.collect();
|
.collect();
|
||||||
res.map(EmbeddingConfigs::new)
|
res.map(RuntimeEmbedders::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_prompt(
|
fn validate_prompt(
|
||||||
|
@ -1970,6 +2044,8 @@ pub fn validate_embedding_settings(
|
||||||
document_template,
|
document_template,
|
||||||
document_template_max_bytes,
|
document_template_max_bytes,
|
||||||
url,
|
url,
|
||||||
|
indexing_fragments,
|
||||||
|
search_fragments,
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
search_embedder,
|
search_embedder,
|
||||||
|
@ -1997,8 +2073,28 @@ pub fn validate_embedding_settings(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(request) = request.as_ref().set() {
|
if let Some(request) = request.as_ref().set() {
|
||||||
let request = crate::vector::rest::Request::new(request.to_owned())
|
let request = crate::vector::rest::RequestData::new(
|
||||||
.map_err(|error| crate::UserError::VectorEmbeddingError(error.into()))?;
|
request.to_owned(),
|
||||||
|
indexing_fragments
|
||||||
|
.as_ref()
|
||||||
|
.set()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|map| map.iter())
|
||||||
|
.filter_map(|(name, fragment)| {
|
||||||
|
Some((name.clone(), fragment.as_ref().map(|fragment| fragment.value.clone())?))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
search_fragments
|
||||||
|
.as_ref()
|
||||||
|
.set()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|map| map.iter())
|
||||||
|
.filter_map(|(name, fragment)| {
|
||||||
|
Some((name.clone(), fragment.as_ref().map(|fragment| fragment.value.clone())?))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.map_err(|error| crate::UserError::VectorEmbeddingError(error.into()))?;
|
||||||
if let Some(response) = response.as_ref().set() {
|
if let Some(response) = response.as_ref().set() {
|
||||||
crate::vector::rest::Response::new(response.to_owned(), &request)
|
crate::vector::rest::Response::new(response.to_owned(), &request)
|
||||||
.map_err(|error| crate::UserError::VectorEmbeddingError(error.into()))?;
|
.map_err(|error| crate::UserError::VectorEmbeddingError(error.into()))?;
|
||||||
|
@ -2017,6 +2113,8 @@ pub fn validate_embedding_settings(
|
||||||
document_template,
|
document_template,
|
||||||
document_template_max_bytes,
|
document_template_max_bytes,
|
||||||
url,
|
url,
|
||||||
|
indexing_fragments,
|
||||||
|
search_fragments,
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
search_embedder,
|
search_embedder,
|
||||||
|
@ -2036,6 +2134,8 @@ pub fn validate_embedding_settings(
|
||||||
&dimensions,
|
&dimensions,
|
||||||
&api_key,
|
&api_key,
|
||||||
&url,
|
&url,
|
||||||
|
&indexing_fragments,
|
||||||
|
&search_fragments,
|
||||||
&request,
|
&request,
|
||||||
&response,
|
&response,
|
||||||
&document_template,
|
&document_template,
|
||||||
|
@ -2114,6 +2214,8 @@ pub fn validate_embedding_settings(
|
||||||
&embedder.dimensions,
|
&embedder.dimensions,
|
||||||
&embedder.api_key,
|
&embedder.api_key,
|
||||||
&embedder.url,
|
&embedder.url,
|
||||||
|
&embedder.indexing_fragments,
|
||||||
|
&embedder.search_fragments,
|
||||||
&embedder.request,
|
&embedder.request,
|
||||||
&embedder.response,
|
&embedder.response,
|
||||||
&embedder.document_template,
|
&embedder.document_template,
|
||||||
|
@ -2169,6 +2271,8 @@ pub fn validate_embedding_settings(
|
||||||
&embedder.dimensions,
|
&embedder.dimensions,
|
||||||
&embedder.api_key,
|
&embedder.api_key,
|
||||||
&embedder.url,
|
&embedder.url,
|
||||||
|
&embedder.indexing_fragments,
|
||||||
|
&embedder.search_fragments,
|
||||||
&embedder.request,
|
&embedder.request,
|
||||||
&embedder.response,
|
&embedder.response,
|
||||||
&embedder.document_template,
|
&embedder.document_template,
|
||||||
|
@ -2201,6 +2305,8 @@ pub fn validate_embedding_settings(
|
||||||
document_template,
|
document_template,
|
||||||
document_template_max_bytes,
|
document_template_max_bytes,
|
||||||
url,
|
url,
|
||||||
|
indexing_fragments,
|
||||||
|
search_fragments,
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
search_embedder,
|
search_embedder,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue