diff --git a/crates/meilisearch-types/src/error.rs b/crates/meilisearch-types/src/error.rs index a864f8aae..8caeb70c2 100644 --- a/crates/meilisearch-types/src/error.rs +++ b/crates/meilisearch-types/src/error.rs @@ -243,8 +243,9 @@ InvalidVectorsType , InvalidRequest , BAD_REQUEST ; InvalidDocumentId , InvalidRequest , BAD_REQUEST ; InvalidDocumentLimit , InvalidRequest , BAD_REQUEST ; InvalidDocumentOffset , InvalidRequest , BAD_REQUEST ; -InvalidEmbedder , InvalidRequest , BAD_REQUEST ; -InvalidHybridQuery , InvalidRequest , BAD_REQUEST ; +InvalidSearchEmbedder , InvalidRequest , BAD_REQUEST ; +InvalidSimilarEmbedder , InvalidRequest , BAD_REQUEST ; +InvalidSearchHybridQuery , InvalidRequest , BAD_REQUEST ; InvalidIndexLimit , InvalidRequest , BAD_REQUEST ; InvalidIndexOffset , InvalidRequest , BAD_REQUEST ; InvalidIndexPrimaryKey , InvalidRequest , BAD_REQUEST ; @@ -443,7 +444,8 @@ impl ErrorCode for milli::Error { UserError::InvalidMinTypoWordLenSetting(_, _) => { Code::InvalidSettingsTypoTolerance } - UserError::InvalidEmbedder(_) => Code::InvalidEmbedder, + UserError::InvalidSearchEmbedder(_) => Code::InvalidSearchEmbedder, + UserError::InvalidSimilarEmbedder(_) => Code::InvalidSimilarEmbedder, UserError::VectorEmbeddingError(_) | UserError::DocumentEmbeddingError(_) => { Code::VectorEmbeddingError } diff --git a/crates/meilisearch/src/routes/indexes/facet_search.rs b/crates/meilisearch/src/routes/indexes/facet_search.rs index 7a41f1f81..4b7ad8fa8 100644 --- a/crates/meilisearch/src/routes/indexes/facet_search.rs +++ b/crates/meilisearch/src/routes/indexes/facet_search.rs @@ -56,7 +56,7 @@ pub struct FacetSearchQuery { pub q: Option, #[deserr(default, error = DeserrJsonError)] pub vector: Option>, - #[deserr(default, error = DeserrJsonError)] + #[deserr(default, error = DeserrJsonError)] pub hybrid: Option, #[deserr(default, error = DeserrJsonError)] pub filter: Option, diff --git a/crates/meilisearch/src/routes/indexes/search.rs b/crates/meilisearch/src/routes/indexes/search.rs index ca3c61753..b4549fc22 100644 --- a/crates/meilisearch/src/routes/indexes/search.rs +++ b/crates/meilisearch/src/routes/indexes/search.rs @@ -121,7 +121,7 @@ pub struct SearchQueryGet { #[deserr(default, error = DeserrQueryParamError)] #[param(value_type = Vec, explode = false)] pub attributes_to_search_on: Option>, - #[deserr(default, error = DeserrQueryParamError)] + #[deserr(default, error = DeserrQueryParamError)] pub hybrid_embedder: Option, #[deserr(default, error = DeserrQueryParamError)] #[param(value_type = f32)] @@ -185,7 +185,7 @@ impl TryFrom for SearchQuery { (None, Some(_)) => { return Err(ResponseError::from_msg( "`hybridEmbedder` is mandatory when `hybridSemanticRatio` is present".into(), - meilisearch_types::error::Code::InvalidHybridQuery, + meilisearch_types::error::Code::InvalidSearchHybridQuery, )); } (Some(embedder), None) => { diff --git a/crates/meilisearch/src/routes/indexes/similar.rs b/crates/meilisearch/src/routes/indexes/similar.rs index 4e0673a7d..64240d498 100644 --- a/crates/meilisearch/src/routes/indexes/similar.rs +++ b/crates/meilisearch/src/routes/indexes/similar.rs @@ -19,8 +19,8 @@ use crate::extractors::authentication::GuardedData; use crate::extractors::sequential_extractor::SeqHandler; use crate::routes::indexes::similar_analytics::{SimilarAggregator, SimilarGET, SimilarPOST}; use crate::search::{ - add_search_rules, perform_similar, RankingScoreThresholdSimilar, RetrieveVectors, SearchKind, - SimilarQuery, SimilarResult, DEFAULT_SEARCH_LIMIT, DEFAULT_SEARCH_OFFSET, + add_search_rules, perform_similar, RankingScoreThresholdSimilar, RetrieveVectors, Route, + SearchKind, SimilarQuery, SimilarResult, DEFAULT_SEARCH_LIMIT, DEFAULT_SEARCH_OFFSET, }; #[derive(OpenApi)] @@ -235,6 +235,7 @@ async fn similar( &index, &query.embedder, None, + Route::Similar, )?; tokio::task::spawn_blocking(move || { @@ -281,7 +282,7 @@ pub struct SimilarQueryGet { #[deserr(default, error = DeserrQueryParamError, default)] #[param(value_type = Option)] pub ranking_score_threshold: Option, - #[deserr(error = DeserrQueryParamError)] + #[deserr(error = DeserrQueryParamError)] pub embedder: String, } diff --git a/crates/meilisearch/src/search/mod.rs b/crates/meilisearch/src/search/mod.rs index abeae55bd..cd970fb2e 100644 --- a/crates/meilisearch/src/search/mod.rs +++ b/crates/meilisearch/src/search/mod.rs @@ -63,7 +63,7 @@ pub struct SearchQuery { pub q: Option, #[deserr(default, error = DeserrJsonError)] pub vector: Option>, - #[deserr(default, error = DeserrJsonError)] + #[deserr(default, error = DeserrJsonError)] pub hybrid: Option, #[deserr(default = DEFAULT_SEARCH_OFFSET(), error = DeserrJsonError)] #[schema(default = DEFAULT_SEARCH_OFFSET)] @@ -276,12 +276,12 @@ impl fmt::Debug for SearchQuery { } #[derive(Debug, Clone, Default, PartialEq, Deserr, ToSchema)] -#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct HybridQuery { #[deserr(default, error = DeserrJsonError, default)] #[schema(value_type = f32, default)] pub semantic_ratio: SemanticRatio, - #[deserr(error = DeserrJsonError)] + #[deserr(error = DeserrJsonError)] pub embedder: String, } @@ -300,8 +300,14 @@ impl SearchKind { embedder_name: &str, vector_len: Option, ) -> Result { - let (embedder_name, embedder, quantized) = - Self::embedder(index_scheduler, index_uid, index, embedder_name, vector_len)?; + let (embedder_name, embedder, quantized) = Self::embedder( + index_scheduler, + index_uid, + index, + embedder_name, + vector_len, + Route::Search, + )?; Ok(Self::SemanticOnly { embedder_name, embedder, quantized }) } @@ -313,8 +319,14 @@ impl SearchKind { semantic_ratio: f32, vector_len: Option, ) -> Result { - let (embedder_name, embedder, quantized) = - Self::embedder(index_scheduler, index_uid, index, embedder_name, vector_len)?; + let (embedder_name, embedder, quantized) = Self::embedder( + index_scheduler, + index_uid, + index, + embedder_name, + vector_len, + Route::Search, + )?; Ok(Self::Hybrid { embedder_name, embedder, quantized, semantic_ratio }) } @@ -324,13 +336,21 @@ impl SearchKind { index: &Index, embedder_name: &str, vector_len: Option, + route: Route, ) -> Result<(String, Arc, bool), ResponseError> { let embedder_configs = index.embedding_configs(&index.read_txn()?)?; let embedders = index_scheduler.embedders(index_uid, embedder_configs)?; let (embedder, _, quantized) = embedders .get(embedder_name) - .ok_or(milli::UserError::InvalidEmbedder(embedder_name.to_owned())) + .ok_or(match route { + Route::Search | Route::MultiSearch => { + milli::UserError::InvalidSearchEmbedder(embedder_name.to_owned()) + } + Route::Similar => { + milli::UserError::InvalidSimilarEmbedder(embedder_name.to_owned()) + } + }) .map_err(milli::Error::from)?; if let Some(vector_len) = vector_len { @@ -401,7 +421,7 @@ pub struct SearchQueryWithIndex { pub q: Option, #[deserr(default, error = DeserrJsonError)] pub vector: Option>, - #[deserr(default, error = DeserrJsonError)] + #[deserr(default, error = DeserrJsonError)] pub hybrid: Option, #[deserr(default, error = DeserrJsonError)] pub offset: Option, @@ -553,7 +573,7 @@ pub struct SimilarQuery { pub limit: usize, #[deserr(default, error = DeserrJsonError)] pub filter: Option, - #[deserr(error = DeserrJsonError)] + #[deserr(error = DeserrJsonError)] pub embedder: String, #[deserr(default, error = DeserrJsonError)] pub attributes_to_retrieve: Option>, @@ -1048,9 +1068,10 @@ pub struct ComputedFacets { pub stats: BTreeMap, } -enum Route { +pub enum Route { Search, MultiSearch, + Similar, } fn compute_facet_distribution_stats>( diff --git a/crates/milli/src/error.rs b/crates/milli/src/error.rs index c1b51f192..79e7770f0 100644 --- a/crates/milli/src/error.rs +++ b/crates/milli/src/error.rs @@ -222,7 +222,9 @@ and can not be more than 511 bytes.", .document_id.to_string() #[error("Too many embedders in the configuration. Found {0}, but limited to 256.")] TooManyEmbedders(usize), #[error("Cannot find embedder with name `{0}`.")] - InvalidEmbedder(String), + InvalidSearchEmbedder(String), + #[error("Cannot find embedder with name `{0}`.")] + InvalidSimilarEmbedder(String), #[error("Too many vectors for document with id {0}: found {1}, but limited to 256.")] TooManyVectors(String, usize), #[error("`.embedders.{embedder_name}`: Field `{field}` unavailable for source `{source_}` (only available for sources: {}). Available fields: {}", diff --git a/crates/milli/src/search/new/vector_sort.rs b/crates/milli/src/search/new/vector_sort.rs index 90377c09c..a25605cfc 100644 --- a/crates/milli/src/search/new/vector_sort.rs +++ b/crates/milli/src/search/new/vector_sort.rs @@ -32,7 +32,7 @@ impl VectorSort { .index .embedder_category_id .get(ctx.txn, embedder_name)? - .ok_or_else(|| crate::UserError::InvalidEmbedder(embedder_name.to_owned()))?; + .ok_or_else(|| crate::UserError::InvalidSearchEmbedder(embedder_name.to_owned()))?; Ok(Self { query: None, diff --git a/crates/milli/src/search/similar.rs b/crates/milli/src/search/similar.rs index 5547d800e..759940f9c 100644 --- a/crates/milli/src/search/similar.rs +++ b/crates/milli/src/search/similar.rs @@ -65,10 +65,9 @@ impl<'a> Similar<'a> { let universe = universe; let embedder_index = - self.index - .embedder_category_id - .get(self.rtxn, &self.embedder_name)? - .ok_or_else(|| crate::UserError::InvalidEmbedder(self.embedder_name.to_owned()))?; + self.index.embedder_category_id.get(self.rtxn, &self.embedder_name)?.ok_or_else( + || crate::UserError::InvalidSimilarEmbedder(self.embedder_name.to_owned()), + )?; let reader = ArroyWrapper::new(self.index.vector_arroy, embedder_index, self.quantized); let results = reader.nns_by_item(