From 8ffb5559a20f7809a429654fe9e9cc70d4b7fa50 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sat, 2 Mar 2024 20:23:54 +0100 Subject: [PATCH] Added the same settings operations found in https://github.com/meilisearch/meilisearch-python/pull/924 --- src/search.rs | 2 +- src/settings.rs | 137 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/src/search.rs b/src/search.rs index 01923b38..c4fdf61e 100644 --- a/src/search.rs +++ b/src/search.rs @@ -1232,7 +1232,7 @@ mod tests { .expect("could not enable the vector store"); assert_eq!(features.vector_store, true); let embedder_setting = crate::Embedder::HuggingFace(crate::HuggingFaceEmbedderSettings { - model: "BAAI/bge-base-en-v1.5".into(), + model: Some("BAAI/bge-base-en-v1.5".into()), revision: None, document_template: Some("{{ doc.value }}".into()), }); diff --git a/src/settings.rs b/src/settings.rs index 2346aeef..7931bf69 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -53,8 +53,9 @@ pub enum Embedder { #[serde(rename_all = "camelCase")] pub struct HuggingFaceEmbedderSettings { /// the BERT embedding model you want to use from HuggingFace - /// Example: `bge-base-en-v1.5` - pub model: String, + /// Defaults to `BAAI/bge-base-en-v1.5` + #[serde(skip_serializing_if = "Option::is_none")] + pub model: Option, #[serde(skip_serializing_if = "Option::is_none")] pub revision: Option, /// if present, document_template must be a [Liquid template](https://shopify.github.io/liquid/). @@ -75,9 +76,12 @@ pub struct OpenapiEmbedderSettings { /// Use [tier 2 keys](https://platform.openai.com/docs/guides/rate-limits/usage-tiers?context=tier-two) or above for optimal performance. pub api_key: String, /// The openapi model name - /// Example: `text-embedding-ada-002` - pub model: String, - pub dimensions: usize, + /// Default: `text-embedding-ada-002` + #[serde(skip_serializing_if = "Option::is_none")] + pub model: Option, + /// Defaults to the default for said model name + #[serde(skip_serializing_if = "Option::is_none")] + pub dimensions: Option, /// if present, document_template must be a [Liquid template](https://shopify.github.io/liquid/). /// Use `{{ doc.attribute }}` to access document field values. /// Meilisearch also exposes a `{{ fields }}` array containing one object per document field, which you may access with `{{ field.name }}` and `{{ field.value }}`. @@ -820,6 +824,49 @@ impl Index { .await } + /// Get [embedders](https://www.meilisearch.com/docs/learn/experimental/vector_search) of the [Index]. + /// + /// ``` + /// # use std::collections::HashMap; + /// # use std::string::String; + /// use meilisearch_sdk::{client::*, CustomEmbedderSettings, Embedder, ExperimentalFeatures, indexes::*, Settings}; + /// # + /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); + /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); + /// # + /// # futures::executor::block_on(async move { + /// let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); + /// # client.create_index("get_embedders", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// let index = client.index("get_embedders"); + /// + /// # let mut features = ExperimentalFeatures::new(&client); + /// # features.set_vector_store(true); + /// # let res = features.update().await.unwrap(); + /// # + /// # let t=index.set_settings(&Settings{ + /// # embedders:Some(HashMap::from([(String::from("default"),Embedder::UserProvided(CustomEmbedderSettings{dimensions:1}))])), + /// # ..Settings::default() + /// # }).await.unwrap(); + /// # t.wait_for_completion(&client, None, None).await.unwrap(); + /// let embedders = index.get_embedders().await.unwrap(); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + #[cfg(feature = "experimental-vector-search")] + pub async fn get_embedders(&self) -> Result, Error> { + request::<(), (), Option>>( + &format!( + "{}/indexes/{}/settings/embedders", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await + .map(|r| r.unwrap_or_default()) + } + /// Update [settings](../settings/struct.Settings) of the [Index]. /// /// Updates in the settings are partial. This means that any parameters corresponding to a `None` value will be left unchanged. @@ -1847,6 +1894,39 @@ impl Index { ) .await } + + /// Reset [embedders](https://www.meilisearch.com/docs/learn/experimental/vector_search) of the [Index]. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*, settings::Settings}; + /// # + /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); + /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); + /// # + /// # futures::executor::block_on(async move { + /// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); + /// # client.create_index("reset_embedders", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// let mut index = client.index("reset_embedders"); + /// + /// let task = index.reset_embedders().await.unwrap(); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + #[cfg(feature = "experimental-vector-search")] + pub async fn reset_embedders(&self) -> Result { + request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/embedders", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await + } } #[cfg(test)] @@ -1882,6 +1962,14 @@ mod tests { assert_eq!(faceting, res); } + #[cfg(feature = "experimental-vector-search")] + #[meilisearch_test] + async fn test_get_embeddings(index: Index) { + let res = index.get_embedders().await.unwrap(); + + assert_eq!(HashMap::new(), res); + } + #[meilisearch_test] async fn test_set_faceting(client: Client, index: Index) { let faceting = FacetingSettings { @@ -1908,6 +1996,23 @@ mod tests { assert_eq!(faceting, res); } + #[cfg(feature = "experimental-vector-search")] + #[meilisearch_test] + async fn test_reset_embedders(client: Client, index: Index) { + let features = crate::ExperimentalFeatures::new(&client) + .set_vector_store(true) + .update() + .await + .expect("could not enable the vector store"); + assert_eq!(features.vector_store, true); + let task_info = index.reset_embedders().await.unwrap(); + client.wait_for_task(task_info, None, None).await.unwrap(); + + let res = index.get_embedders().await.unwrap(); + + assert_eq!(HashMap::new(), res); + } + #[meilisearch_test] async fn test_get_dictionary(index: Index) { let dictionary: Vec = vec![]; @@ -2084,6 +2189,28 @@ mod tests { assert_eq!(expected, res); } + #[cfg(feature = "experimental-vector-search")] + #[meilisearch_test] + async fn test_set_embedding_settings(client: Client, index: Index) { + let features = crate::ExperimentalFeatures::new(&client) + .set_vector_store(true) + .update() + .await + .expect("could not enable the vector store"); + assert_eq!(features.vector_store, true); + + let custom_embedder = Embedder::UserProvided(CustomEmbedderSettings { dimensions: 2 }); + let embeddings = HashMap::from([("default".into(), custom_embedder)]); + let settings = Settings::new().with_embedders(embeddings.clone()); + + let task_info = index.set_settings(&settings).await.unwrap(); + client.wait_for_task(task_info, None, None).await.unwrap(); + + let res = index.get_embedders().await.unwrap(); + + assert_eq!(embeddings, res); + } + #[meilisearch_test] async fn test_reset_proximity_precision(index: Index) { let expected = "byWord".to_string();