mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-26 23:04:26 +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);
|
.unwrap_or_else(BTreeSet::new);
|
||||||
let distinct_field = self.distinct_field(&txn)?.map(String::from);
|
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 {
|
Ok(Settings {
|
||||||
displayed_attributes: Some(displayed_attributes),
|
displayed_attributes: Some(displayed_attributes),
|
||||||
searchable_attributes: Some(searchable_attributes),
|
searchable_attributes: Some(searchable_attributes),
|
||||||
@ -91,6 +104,7 @@ impl Index {
|
|||||||
ranking_rules: Some(Some(criteria)),
|
ranking_rules: Some(Some(criteria)),
|
||||||
stop_words: Some(Some(stop_words)),
|
stop_words: Some(Some(stop_words)),
|
||||||
distinct_attribute: Some(distinct_field),
|
distinct_attribute: Some(distinct_field),
|
||||||
|
synonyms: Some(Some(synonyms)),
|
||||||
_kind: PhantomData,
|
_kind: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::collections::{BTreeSet, HashSet};
|
use std::collections::{BTreeSet, BTreeMap, HashSet};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
@ -70,6 +70,12 @@ pub struct Settings<T> {
|
|||||||
deserialize_with = "deserialize_some",
|
deserialize_with = "deserialize_some",
|
||||||
skip_serializing_if = "Option::is_none"
|
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>>,
|
pub distinct_attribute: Option<Option<String>>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
@ -84,6 +90,7 @@ impl Settings<Checked> {
|
|||||||
filterable_attributes: Some(None),
|
filterable_attributes: Some(None),
|
||||||
ranking_rules: Some(None),
|
ranking_rules: Some(None),
|
||||||
stop_words: Some(None),
|
stop_words: Some(None),
|
||||||
|
synonyms: Some(None),
|
||||||
distinct_attribute: Some(None),
|
distinct_attribute: Some(None),
|
||||||
_kind: PhantomData,
|
_kind: PhantomData,
|
||||||
}
|
}
|
||||||
@ -96,6 +103,7 @@ impl Settings<Checked> {
|
|||||||
filterable_attributes,
|
filterable_attributes,
|
||||||
ranking_rules,
|
ranking_rules,
|
||||||
stop_words,
|
stop_words,
|
||||||
|
synonyms,
|
||||||
distinct_attribute,
|
distinct_attribute,
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
@ -106,6 +114,7 @@ impl Settings<Checked> {
|
|||||||
filterable_attributes,
|
filterable_attributes,
|
||||||
ranking_rules,
|
ranking_rules,
|
||||||
stop_words,
|
stop_words,
|
||||||
|
synonyms,
|
||||||
distinct_attribute,
|
distinct_attribute,
|
||||||
_kind: PhantomData,
|
_kind: PhantomData,
|
||||||
}
|
}
|
||||||
@ -142,6 +151,7 @@ impl Settings<Unchecked> {
|
|||||||
filterable_attributes: self.filterable_attributes,
|
filterable_attributes: self.filterable_attributes,
|
||||||
ranking_rules: self.ranking_rules,
|
ranking_rules: self.ranking_rules,
|
||||||
stop_words: self.stop_words,
|
stop_words: self.stop_words,
|
||||||
|
synonyms: self.synonyms,
|
||||||
distinct_attribute: self.distinct_attribute,
|
distinct_attribute: self.distinct_attribute,
|
||||||
_kind: PhantomData,
|
_kind: PhantomData,
|
||||||
}
|
}
|
||||||
@ -267,7 +277,14 @@ impl Index {
|
|||||||
if let Some(ref stop_words) = settings.stop_words {
|
if let Some(ref stop_words) = settings.stop_words {
|
||||||
match stop_words {
|
match stop_words {
|
||||||
Some(stop_words) => builder.set_stop_words(stop_words.clone()),
|
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,
|
filterable_attributes: None,
|
||||||
ranking_rules: None,
|
ranking_rules: None,
|
||||||
stop_words: None,
|
stop_words: None,
|
||||||
|
synonyms: None,
|
||||||
distinct_attribute: None,
|
distinct_attribute: None,
|
||||||
_kind: PhantomData::<Unchecked>,
|
_kind: PhantomData::<Unchecked>,
|
||||||
};
|
};
|
||||||
@ -351,6 +369,7 @@ mod test {
|
|||||||
filterable_attributes: None,
|
filterable_attributes: None,
|
||||||
ranking_rules: None,
|
ranking_rules: None,
|
||||||
stop_words: None,
|
stop_words: None,
|
||||||
|
synonyms: None,
|
||||||
distinct_attribute: None,
|
distinct_attribute: None,
|
||||||
_kind: PhantomData::<Unchecked>,
|
_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
|
/// 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> {
|
impl From<Settings> for index_controller::Settings<Unchecked> {
|
||||||
fn from(settings: Settings) -> Self {
|
fn from(settings: Settings) -> Self {
|
||||||
if settings.synonyms.flatten().is_some() {
|
|
||||||
error!("`synonyms` are not yet implemented and thus will be ignored");
|
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
distinct_attribute: settings.distinct_attribute,
|
distinct_attribute: settings.distinct_attribute,
|
||||||
// we need to convert the old `Vec<String>` into a `BTreeSet<String>`
|
// 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())),
|
}).collect())),
|
||||||
// we need to convert the old `Vec<String>` into a `BTreeSet<String>`
|
// 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())),
|
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,
|
_kind: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ pub enum UpdateResult {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum UpdateMeta {
|
pub enum UpdateMeta {
|
||||||
|
@ -43,7 +43,6 @@ macro_rules! create_app {
|
|||||||
.configure(index::services)
|
.configure(index::services)
|
||||||
.configure(search::services)
|
.configure(search::services)
|
||||||
.configure(settings::services)
|
.configure(settings::services)
|
||||||
.configure(synonym::services)
|
|
||||||
.configure(health::services)
|
.configure(health::services)
|
||||||
.configure(stats::services)
|
.configure(stats::services)
|
||||||
.configure(key::services)
|
.configure(key::services)
|
||||||
|
@ -15,9 +15,9 @@ pub mod key;
|
|||||||
pub mod search;
|
pub mod search;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod stats;
|
pub mod stats;
|
||||||
pub mod synonym;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
#[allow(clippy::clippy::large_enum_variant)]
|
||||||
#[serde(tag = "name")]
|
#[serde(tag = "name")]
|
||||||
pub enum UpdateType {
|
pub enum UpdateType {
|
||||||
ClearAll,
|
ClearAll,
|
||||||
|
@ -97,6 +97,12 @@ make_setting_route!(
|
|||||||
stop_words
|
stop_words
|
||||||
);
|
);
|
||||||
|
|
||||||
|
make_setting_route!(
|
||||||
|
"/indexes/{index_uid}/settings/synonyms",
|
||||||
|
std::collections::BTreeMap<String, Vec<String>>,
|
||||||
|
synonyms
|
||||||
|
);
|
||||||
|
|
||||||
make_setting_route!(
|
make_setting_route!(
|
||||||
"/indexes/{index_uid}/settings/distinct-attribute",
|
"/indexes/{index_uid}/settings/distinct-attribute",
|
||||||
String,
|
String,
|
||||||
@ -131,6 +137,7 @@ create_services!(
|
|||||||
searchable_attributes,
|
searchable_attributes,
|
||||||
distinct_attribute,
|
distinct_attribute,
|
||||||
stop_words,
|
stop_words,
|
||||||
|
synonyms,
|
||||||
ranking_rules
|
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;
|
let (response, code) = index.settings().await;
|
||||||
assert_eq!(code, 200);
|
assert_eq!(code, 200);
|
||||||
let settings = response.as_object().unwrap();
|
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["displayedAttributes"], json!(["*"]));
|
||||||
assert_eq!(settings["searchableAttributes"], json!(["*"]));
|
assert_eq!(settings["searchableAttributes"], json!(["*"]));
|
||||||
assert_eq!(settings["filterableAttributes"], json!([]));
|
assert_eq!(settings["filterableAttributes"], json!([]));
|
||||||
@ -87,7 +87,7 @@ async fn reset_all_settings() {
|
|||||||
index.wait_update_id(0).await;
|
index.wait_update_id(0).await;
|
||||||
|
|
||||||
index
|
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;
|
.await;
|
||||||
index.wait_update_id(1).await;
|
index.wait_update_id(1).await;
|
||||||
let (response, code) = index.settings().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["displayedAttributes"], json!(["name", "age"]));
|
||||||
assert_eq!(response["searchableAttributes"], json!(["name"]));
|
assert_eq!(response["searchableAttributes"], json!(["name"]));
|
||||||
assert_eq!(response["stopWords"], json!(["the"]));
|
assert_eq!(response["stopWords"], json!(["the"]));
|
||||||
|
assert_eq!(
|
||||||
|
response["synonyms"],
|
||||||
|
json!({"puppy": ["dog", "doggo", "potat"] })
|
||||||
|
);
|
||||||
assert_eq!(response["filterableAttributes"], json!(["age"]));
|
assert_eq!(response["filterableAttributes"], json!(["age"]));
|
||||||
|
|
||||||
index.delete_settings().await;
|
index.delete_settings().await;
|
||||||
@ -106,6 +110,7 @@ async fn reset_all_settings() {
|
|||||||
assert_eq!(response["searchableAttributes"], json!(["*"]));
|
assert_eq!(response["searchableAttributes"], json!(["*"]));
|
||||||
assert_eq!(response["stopWords"], json!([]));
|
assert_eq!(response["stopWords"], json!([]));
|
||||||
assert_eq!(response["filterableAttributes"], json!([]));
|
assert_eq!(response["filterableAttributes"], json!([]));
|
||||||
|
assert_eq!(response["synonyms"], json!({}));
|
||||||
|
|
||||||
let (response, code) = index.get_document(1, None).await;
|
let (response, code) = index.get_document(1, None).await;
|
||||||
assert_eq!(code, 200);
|
assert_eq!(code, 200);
|
||||||
@ -184,5 +189,6 @@ test_setting_routes!(
|
|||||||
filterable_attributes,
|
filterable_attributes,
|
||||||
displayed_attributes,
|
displayed_attributes,
|
||||||
searchable_attributes,
|
searchable_attributes,
|
||||||
stop_words
|
stop_words,
|
||||||
|
synonyms
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user