diff --git a/meilisearch-http/src/index/mod.rs b/meilisearch-http/src/index/mod.rs index 782c40d37..cb942a7b8 100644 --- a/meilisearch-http/src/index/mod.rs +++ b/meilisearch-http/src/index/mod.rs @@ -84,6 +84,17 @@ impl Index { .unwrap_or_else(BTreeSet::new); let distinct_field = self.distinct_field(&txn)?.map(String::from); + let synonyms = self + .synonyms(&txn)? + .iter() + .map(|(key, values)| { + ( + key.join(" "), + values.iter().map(|value| value.join(" ")).collect(), + ) + }) + .collect(); + Ok(Settings { displayed_attributes: Some(displayed_attributes), searchable_attributes: Some(searchable_attributes), @@ -91,6 +102,7 @@ impl Index { ranking_rules: Some(Some(criteria)), stop_words: Some(Some(stop_words)), distinct_attribute: Some(distinct_field), + synonyms: Some(Some(synonyms)), _kind: PhantomData, }) } diff --git a/meilisearch-http/src/index/updates.rs b/meilisearch-http/src/index/updates.rs index fa26f6bee..3e31cd75c 100644 --- a/meilisearch-http/src/index/updates.rs +++ b/meilisearch-http/src/index/updates.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeSet, HashSet}; +use std::collections::{BTreeSet, BTreeMap, HashSet}; use std::io; use std::marker::PhantomData; use std::num::NonZeroUsize; @@ -70,6 +70,12 @@ pub struct Settings { deserialize_with = "deserialize_some", skip_serializing_if = "Option::is_none" )] + pub synonyms: Option>>>, + #[serde( + default, + deserialize_with = "deserialize_some", + skip_serializing_if = "Option::is_none" + )] pub distinct_attribute: Option>, #[serde(skip)] @@ -84,6 +90,7 @@ impl Settings { filterable_attributes: Some(None), ranking_rules: Some(None), stop_words: Some(None), + synonyms: Some(None), distinct_attribute: Some(None), _kind: PhantomData, } @@ -96,6 +103,7 @@ impl Settings { filterable_attributes, ranking_rules, stop_words, + synonyms, distinct_attribute, .. } = self; @@ -106,6 +114,7 @@ impl Settings { filterable_attributes, ranking_rules, stop_words, + synonyms, distinct_attribute, _kind: PhantomData, } @@ -142,6 +151,7 @@ impl Settings { filterable_attributes: self.filterable_attributes, ranking_rules: self.ranking_rules, stop_words: self.stop_words, + synonyms: self.synonyms, distinct_attribute: self.distinct_attribute, _kind: PhantomData, } @@ -271,6 +281,13 @@ impl Index { } } + if let Some(ref synonyms) = settings.synonyms { + match synonyms { + Some(synonyms) => builder.set_synonyms(synonyms.clone().into_iter().collect()), + _ => builder.reset_synonyms(), + } + } + if let Some(ref distinct_attribute) = settings.distinct_attribute { match distinct_attribute { Some(attr) => builder.set_distinct_field(attr.clone()), @@ -332,6 +349,7 @@ mod test { filterable_attributes: None, ranking_rules: None, stop_words: None, + synonyms: None, distinct_attribute: None, _kind: PhantomData::, }; @@ -351,6 +369,7 @@ mod test { filterable_attributes: None, ranking_rules: None, stop_words: None, + synonyms: None, distinct_attribute: None, _kind: PhantomData::, }; diff --git a/meilisearch-http/src/index_controller/dump_actor/loaders/v1.rs b/meilisearch-http/src/index_controller/dump_actor/loaders/v1.rs index 247b81a95..a7f1aa8d1 100644 --- a/meilisearch-http/src/index_controller/dump_actor/loaders/v1.rs +++ b/meilisearch-http/src/index_controller/dump_actor/loaders/v1.rs @@ -133,9 +133,6 @@ fn load_index( /// we need to **always** be able to convert the old settings to the settings currently being used impl From for index_controller::Settings { fn from(settings: Settings) -> Self { - if settings.synonyms.flatten().is_some() { - error!("`synonyms` are not yet implemented and thus will be ignored"); - } Self { distinct_attribute: settings.distinct_attribute, // we need to convert the old `Vec` into a `BTreeSet` @@ -167,6 +164,8 @@ impl From for index_controller::Settings { }).collect())), // we need to convert the old `Vec` into a `BTreeSet` stop_words: settings.stop_words.map(|o| o.map(|vec| vec.into_iter().collect())), + // we need to convert the old `Vec` into a `BTreeMap` + synonyms: settings.synonyms.map(|o| o.map(|vec| vec.into_iter().collect())), _kind: PhantomData, } } diff --git a/meilisearch-http/src/lib.rs b/meilisearch-http/src/lib.rs index 26b6a784c..fb80aa3d6 100644 --- a/meilisearch-http/src/lib.rs +++ b/meilisearch-http/src/lib.rs @@ -43,7 +43,6 @@ macro_rules! create_app { .configure(index::services) .configure(search::services) .configure(settings::services) - .configure(synonym::services) .configure(health::services) .configure(stats::services) .configure(key::services) diff --git a/meilisearch-http/src/routes/mod.rs b/meilisearch-http/src/routes/mod.rs index e1db8147d..948e263cc 100644 --- a/meilisearch-http/src/routes/mod.rs +++ b/meilisearch-http/src/routes/mod.rs @@ -15,7 +15,6 @@ pub mod key; pub mod search; pub mod settings; pub mod stats; -pub mod synonym; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "name")] diff --git a/meilisearch-http/src/routes/settings/mod.rs b/meilisearch-http/src/routes/settings/mod.rs index ca8dd03ce..45d49132c 100644 --- a/meilisearch-http/src/routes/settings/mod.rs +++ b/meilisearch-http/src/routes/settings/mod.rs @@ -97,6 +97,12 @@ make_setting_route!( stop_words ); +make_setting_route!( + "/indexes/{index_uid}/settings/synonyms", + std::collections::BTreeMap>, + synonyms +); + make_setting_route!( "/indexes/{index_uid}/settings/distinct-attribute", String, @@ -131,6 +137,7 @@ create_services!( searchable_attributes, distinct_attribute, stop_words, + synonyms, ranking_rules ); diff --git a/meilisearch-http/src/routes/synonym.rs b/meilisearch-http/src/routes/synonym.rs deleted file mode 100644 index 4106e3754..000000000 --- a/meilisearch-http/src/routes/synonym.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::collections::BTreeMap; - -use actix_web::{delete, get, post}; -use actix_web::{web, HttpResponse}; - -use crate::error::ResponseError; -use crate::helpers::Authentication; -use crate::routes::IndexParam; -use crate::Data; - -pub fn services(cfg: &mut web::ServiceConfig) { - cfg.service(get).service(update).service(delete); -} - -#[get( - "/indexes/{index_uid}/settings/synonyms", - wrap = "Authentication::Private" -)] -async fn get( - _data: web::Data, - _path: web::Path, -) -> Result { - todo!() -} - -#[post( - "/indexes/{index_uid}/settings/synonyms", - wrap = "Authentication::Private" -)] -async fn update( - _data: web::Data, - _path: web::Path, - _body: web::Json>>, -) -> Result { - todo!() -} - -#[delete( - "/indexes/{index_uid}/settings/synonyms", - wrap = "Authentication::Private" -)] -async fn delete( - _data: web::Data, - _path: web::Path, -) -> Result { - todo!() -} diff --git a/meilisearch-http/tests/settings/get_settings.rs b/meilisearch-http/tests/settings/get_settings.rs index 4fd9fa724..a4ee6a4d3 100644 --- a/meilisearch-http/tests/settings/get_settings.rs +++ b/meilisearch-http/tests/settings/get_settings.rs @@ -16,7 +16,7 @@ async fn get_settings() { let (response, code) = index.settings().await; assert_eq!(code, 200); let settings = response.as_object().unwrap(); - assert_eq!(settings.keys().len(), 6); + assert_eq!(settings.keys().len(), 7); assert_eq!(settings["displayedAttributes"], json!(["*"])); assert_eq!(settings["searchableAttributes"], json!(["*"])); assert_eq!(settings["filterableAttributes"], json!([])); @@ -87,7 +87,7 @@ async fn reset_all_settings() { index.wait_update_id(0).await; index - .update_settings(json!({"displayedAttributes": ["name", "age"], "searchableAttributes": ["name"], "stopWords": ["the"], "filterableAttributes": ["age"] })) + .update_settings(json!({"displayedAttributes": ["name", "age"], "searchableAttributes": ["name"], "stopWords": ["the"], "filterableAttributes": ["age"], "synonyms": {"puppy": ["dog", "doggo", "potat"] }})) .await; index.wait_update_id(1).await; let (response, code) = index.settings().await; @@ -95,6 +95,10 @@ async fn reset_all_settings() { assert_eq!(response["displayedAttributes"], json!(["name", "age"])); assert_eq!(response["searchableAttributes"], json!(["name"])); assert_eq!(response["stopWords"], json!(["the"])); + assert_eq!( + response["synonyms"], + json!({"puppy": ["dog", "doggo", "potat"] }) + ); assert_eq!(response["filterableAttributes"], json!(["age"])); index.delete_settings().await; @@ -110,6 +114,7 @@ async fn reset_all_settings() { let (response, code) = index.get_document(1, None).await; assert_eq!(code, 200); assert!(response.as_object().unwrap().get("age").is_some()); + assert_eq!(response["synonyms"], json!({})); } #[actix_rt::test] @@ -184,5 +189,6 @@ test_setting_routes!( filterable_attributes, displayed_attributes, searchable_attributes, - stop_words + stop_words, + synonyms );