mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-22 21:04:27 +01:00
Merge #196
196: Implements the synonyms in transplant r=MarinPostma a=irevoire closes #18 Co-authored-by: Tamo <tamo@meilisearch.com> Co-authored-by: marin postma <postma.marin@protonmail.com>
This commit is contained in:
commit
13e864d29f
@ -84,6 +84,19 @@ impl Index {
|
||||
.unwrap_or_else(BTreeSet::new);
|
||||
let distinct_field = self.distinct_field(&txn)?.map(String::from);
|
||||
|
||||
// in milli each word in the synonyms map were split on their separator. Since we lost
|
||||
// this information we are going to put space between words.
|
||||
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 +104,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,
|
||||
})
|
||||
}
|
||||
|
@ -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<T> {
|
||||
deserialize_with = "deserialize_some",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub synonyms: Option<Option<BTreeMap<String, Vec<String>>>>,
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "deserialize_some",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub distinct_attribute: Option<Option<String>>,
|
||||
|
||||
#[serde(skip)]
|
||||
@ -84,6 +90,7 @@ impl Settings<Checked> {
|
||||
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<Checked> {
|
||||
filterable_attributes,
|
||||
ranking_rules,
|
||||
stop_words,
|
||||
synonyms,
|
||||
distinct_attribute,
|
||||
..
|
||||
} = self;
|
||||
@ -106,6 +114,7 @@ impl Settings<Checked> {
|
||||
filterable_attributes,
|
||||
ranking_rules,
|
||||
stop_words,
|
||||
synonyms,
|
||||
distinct_attribute,
|
||||
_kind: PhantomData,
|
||||
}
|
||||
@ -142,6 +151,7 @@ impl Settings<Unchecked> {
|
||||
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,
|
||||
}
|
||||
@ -267,7 +277,14 @@ impl Index {
|
||||
if let Some(ref stop_words) = settings.stop_words {
|
||||
match stop_words {
|
||||
Some(stop_words) => builder.set_stop_words(stop_words.clone()),
|
||||
_ => builder.reset_stop_words(),
|
||||
None => builder.reset_stop_words(),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref synonyms) = settings.synonyms {
|
||||
match synonyms {
|
||||
Some(synonyms) => builder.set_synonyms(synonyms.clone().into_iter().collect()),
|
||||
None => builder.reset_synonyms(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,6 +349,7 @@ mod test {
|
||||
filterable_attributes: None,
|
||||
ranking_rules: None,
|
||||
stop_words: None,
|
||||
synonyms: None,
|
||||
distinct_attribute: None,
|
||||
_kind: PhantomData::<Unchecked>,
|
||||
};
|
||||
@ -351,6 +369,7 @@ mod test {
|
||||
filterable_attributes: None,
|
||||
ranking_rules: None,
|
||||
stop_words: None,
|
||||
synonyms: None,
|
||||
distinct_attribute: None,
|
||||
_kind: PhantomData::<Unchecked>,
|
||||
};
|
||||
|
@ -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<Settings> for index_controller::Settings<Unchecked> {
|
||||
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<String>` into a `BTreeSet<String>`
|
||||
@ -167,6 +164,8 @@ impl From<Settings> for index_controller::Settings<Unchecked> {
|
||||
}).collect())),
|
||||
// we need to convert the old `Vec<String>` into a `BTreeSet<String>`
|
||||
stop_words: settings.stop_words.map(|o| o.map(|vec| vec.into_iter().collect())),
|
||||
// we need to convert the old `Vec<String>` into a `BTreeMap<String>`
|
||||
synonyms: settings.synonyms.map(|o| o.map(|vec| vec.into_iter().collect())),
|
||||
_kind: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub enum UpdateResult {
|
||||
Other,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum UpdateMeta {
|
||||
|
@ -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)
|
||||
|
@ -15,9 +15,9 @@ pub mod key;
|
||||
pub mod search;
|
||||
pub mod settings;
|
||||
pub mod stats;
|
||||
pub mod synonym;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[allow(clippy::clippy::large_enum_variant)]
|
||||
#[serde(tag = "name")]
|
||||
pub enum UpdateType {
|
||||
ClearAll,
|
||||
|
@ -97,6 +97,12 @@ make_setting_route!(
|
||||
stop_words
|
||||
);
|
||||
|
||||
make_setting_route!(
|
||||
"/indexes/{index_uid}/settings/synonyms",
|
||||
std::collections::BTreeMap<String, Vec<String>>,
|
||||
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
|
||||
);
|
||||
|
||||
|
@ -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<Data>,
|
||||
_path: web::Path<IndexParam>,
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[post(
|
||||
"/indexes/{index_uid}/settings/synonyms",
|
||||
wrap = "Authentication::Private"
|
||||
)]
|
||||
async fn update(
|
||||
_data: web::Data<Data>,
|
||||
_path: web::Path<IndexParam>,
|
||||
_body: web::Json<BTreeMap<String, Vec<String>>>,
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[delete(
|
||||
"/indexes/{index_uid}/settings/synonyms",
|
||||
wrap = "Authentication::Private"
|
||||
)]
|
||||
async fn delete(
|
||||
_data: web::Data<Data>,
|
||||
_path: web::Path<IndexParam>,
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
todo!()
|
||||
}
|
@ -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;
|
||||
@ -106,6 +110,7 @@ async fn reset_all_settings() {
|
||||
assert_eq!(response["searchableAttributes"], json!(["*"]));
|
||||
assert_eq!(response["stopWords"], json!([]));
|
||||
assert_eq!(response["filterableAttributes"], json!([]));
|
||||
assert_eq!(response["synonyms"], json!({}));
|
||||
|
||||
let (response, code) = index.get_document(1, None).await;
|
||||
assert_eq!(code, 200);
|
||||
@ -184,5 +189,6 @@ test_setting_routes!(
|
||||
filterable_attributes,
|
||||
displayed_attributes,
|
||||
searchable_attributes,
|
||||
stop_words
|
||||
stop_words,
|
||||
synonyms
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user