mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-30 09:04:59 +08:00
Support synonyms sinergies
This commit is contained in:
parent
41c9e8856a
commit
d57026cd96
@ -194,3 +194,266 @@ async fn set_and_search() {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn advanced_synergies() {
|
||||||
|
let documents = json!([
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"content": "J.R.R. Tolkien",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"content": "J. R. R. Tolkien",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"content": "jrr Tolkien",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"content": "J.K. Rowlings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"content": "J. K. Rowlings",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"content": "jk Rowlings",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
let server = Server::new().await;
|
||||||
|
let index = server.index("test");
|
||||||
|
|
||||||
|
index.add_documents(documents, None).await;
|
||||||
|
index.wait_task(0).await;
|
||||||
|
|
||||||
|
let (_response, _code) = index
|
||||||
|
.update_settings(json!({
|
||||||
|
"dictionary": ["J.R.R.", "J. R. R.", "J.K.", "J. K."],
|
||||||
|
"synonyms": {
|
||||||
|
"J.R.R.": ["jrr", "J. R. R."],
|
||||||
|
"J. R. R.": ["jrr", "J.R.R."],
|
||||||
|
"jrr": ["J.R.R.", "J. R. R."],
|
||||||
|
"J.K.": ["jk", "J. K."],
|
||||||
|
"J. K.": ["jk", "J.K."],
|
||||||
|
"jk": ["J.K.", "J. K."],
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.await;
|
||||||
|
index.wait_task(1).await;
|
||||||
|
|
||||||
|
index
|
||||||
|
.search(json!({"q": "J.R.R.", "attributesToHighlight": ["content"]}), |response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"content": "J.R.R. Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "1",
|
||||||
|
"content": "<em>J.R.R.</em> Tolkien"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"content": "J. R. R. Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "2",
|
||||||
|
"content": "<em>J. R. R.</em> Tolkien"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"content": "jrr Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "3",
|
||||||
|
"content": "<em>jrr</em> Tolkien"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
index
|
||||||
|
.search(json!({"q": "jrr", "attributesToHighlight": ["content"]}), |response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"content": "jrr Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "3",
|
||||||
|
"content": "<em>jrr</em> Tolkien"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"content": "J.R.R. Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "1",
|
||||||
|
"content": "<em>J.R.R.</em> Tolkien"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"content": "J. R. R. Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "2",
|
||||||
|
"content": "<em>J. R. R.</em> Tolkien"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
index
|
||||||
|
.search(json!({"q": "J. R. R.", "attributesToHighlight": ["content"]}), |response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"content": "J. R. R. Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "2",
|
||||||
|
"content": "<em>J. R. R.</em> Tolkien"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"content": "J.R.R. Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "1",
|
||||||
|
"content": "<em>J.R.R.</em> Tolkien"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"content": "jrr Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "3",
|
||||||
|
"content": "<em>jrr</em> Tolkien"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
index
|
||||||
|
.search(json!({"q": "jk", "attributesToHighlight": ["content"]}), |response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"content": "jk Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "6",
|
||||||
|
"content": "<em>jk</em> Rowlings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"content": "J.K. Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "4",
|
||||||
|
"content": "<em>J.K.</em> Rowlings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"content": "J. K. Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "5",
|
||||||
|
"content": "<em>J. K.</em> Rowlings"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
index
|
||||||
|
.search(json!({"q": "J.K.", "attributesToHighlight": ["content"]}), |response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"content": "J.K. Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "4",
|
||||||
|
"content": "<em>J.K.</em> Rowlings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"content": "J. K. Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "5",
|
||||||
|
"content": "<em>J. K.</em> Rowlings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"content": "jk Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "6",
|
||||||
|
"content": "<em>jk</em> Rowlings"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
index
|
||||||
|
.search(json!({"q": "J. K.", "attributesToHighlight": ["content"]}), |response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"content": "J. K. Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "5",
|
||||||
|
"content": "<em>J. K.</em> Rowlings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"content": "J.K. Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "4",
|
||||||
|
"content": "<em>J.K.</em> Rowlings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"content": "jk Rowlings",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "6",
|
||||||
|
"content": "<em>jk</em> Rowlings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"content": "J. R. R. Tolkien",
|
||||||
|
"_formatted": {
|
||||||
|
"id": "2",
|
||||||
|
"content": "<em>J. R.</em> R. Tolkien"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
@ -491,57 +491,78 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_non_separator_tokens(&mut self) -> Result<bool> {
|
fn update_non_separator_tokens(&mut self) -> Result<bool> {
|
||||||
match self.non_separator_tokens {
|
let changes = match self.non_separator_tokens {
|
||||||
Setting::Set(ref non_separator_tokens) => {
|
Setting::Set(ref non_separator_tokens) => {
|
||||||
let current = self.index.non_separator_tokens(self.wtxn)?;
|
let current = self.index.non_separator_tokens(self.wtxn)?;
|
||||||
|
|
||||||
// Does the new list differ from the previous one?
|
// Does the new list differ from the previous one?
|
||||||
if current.map_or(true, |current| ¤t != non_separator_tokens) {
|
if current.map_or(true, |current| ¤t != non_separator_tokens) {
|
||||||
self.index.put_non_separator_tokens(self.wtxn, non_separator_tokens)?;
|
self.index.put_non_separator_tokens(self.wtxn, non_separator_tokens)?;
|
||||||
Ok(true)
|
true
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Setting::Reset => Ok(self.index.delete_non_separator_tokens(self.wtxn)?),
|
Setting::Reset => self.index.delete_non_separator_tokens(self.wtxn)?,
|
||||||
Setting::NotSet => Ok(false),
|
Setting::NotSet => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// the synonyms must be updated if non separator tokens have been updated.
|
||||||
|
if changes {
|
||||||
|
self.update_synonyms()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(changes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_separator_tokens(&mut self) -> Result<bool> {
|
fn update_separator_tokens(&mut self) -> Result<bool> {
|
||||||
match self.separator_tokens {
|
let changes = match self.separator_tokens {
|
||||||
Setting::Set(ref separator_tokens) => {
|
Setting::Set(ref separator_tokens) => {
|
||||||
let current = self.index.separator_tokens(self.wtxn)?;
|
let current = self.index.separator_tokens(self.wtxn)?;
|
||||||
|
|
||||||
// Does the new list differ from the previous one?
|
// Does the new list differ from the previous one?
|
||||||
if current.map_or(true, |current| ¤t != separator_tokens) {
|
if current.map_or(true, |current| ¤t != separator_tokens) {
|
||||||
self.index.put_separator_tokens(self.wtxn, separator_tokens)?;
|
self.index.put_separator_tokens(self.wtxn, separator_tokens)?;
|
||||||
Ok(true)
|
true
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Setting::Reset => Ok(self.index.delete_separator_tokens(self.wtxn)?),
|
Setting::Reset => self.index.delete_separator_tokens(self.wtxn)?,
|
||||||
Setting::NotSet => Ok(false),
|
Setting::NotSet => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// the synonyms must be updated if separator tokens have been updated.
|
||||||
|
if changes {
|
||||||
|
self.update_synonyms()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(changes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_dictionary(&mut self) -> Result<bool> {
|
fn update_dictionary(&mut self) -> Result<bool> {
|
||||||
match self.dictionary {
|
let changes = match self.dictionary {
|
||||||
Setting::Set(ref dictionary) => {
|
Setting::Set(ref dictionary) => {
|
||||||
let current = self.index.dictionary(self.wtxn)?;
|
let current = self.index.dictionary(self.wtxn)?;
|
||||||
|
|
||||||
// Does the new list differ from the previous one?
|
// Does the new list differ from the previous one?
|
||||||
if current.map_or(true, |current| ¤t != dictionary) {
|
if current.map_or(true, |current| ¤t != dictionary) {
|
||||||
self.index.put_dictionary(self.wtxn, dictionary)?;
|
self.index.put_dictionary(self.wtxn, dictionary)?;
|
||||||
Ok(true)
|
true
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Setting::Reset => Ok(self.index.delete_dictionary(self.wtxn)?),
|
Setting::Reset => self.index.delete_dictionary(self.wtxn)?,
|
||||||
Setting::NotSet => Ok(false),
|
Setting::NotSet => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// the synonyms must be updated if dictionary has been updated.
|
||||||
|
if changes {
|
||||||
|
self.update_synonyms()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(changes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_synonyms(&mut self) -> Result<bool> {
|
fn update_synonyms(&mut self) -> Result<bool> {
|
||||||
@ -565,6 +586,21 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> {
|
|||||||
if let Some(ref stop_words) = stop_words {
|
if let Some(ref stop_words) = stop_words {
|
||||||
builder.stop_words(stop_words);
|
builder.stop_words(stop_words);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let separators = self.index.allowed_separators(self.wtxn)?;
|
||||||
|
let separators: Option<Vec<_>> =
|
||||||
|
separators.as_ref().map(|x| x.iter().map(String::as_str).collect());
|
||||||
|
if let Some(ref separators) = separators {
|
||||||
|
builder.separators(separators);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dictionary = self.index.dictionary(self.wtxn)?;
|
||||||
|
let dictionary: Option<Vec<_>> =
|
||||||
|
dictionary.as_ref().map(|x| x.iter().map(String::as_str).collect());
|
||||||
|
if let Some(ref dictionary) = dictionary {
|
||||||
|
builder.words_dict(dictionary);
|
||||||
|
}
|
||||||
|
|
||||||
let tokenizer = builder.build();
|
let tokenizer = builder.build();
|
||||||
|
|
||||||
let mut new_synonyms = HashMap::new();
|
let mut new_synonyms = HashMap::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user