From 0c3fa8cbc408d923e4c71984eb5404bdbbcc740c Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Wed, 6 Dec 2023 14:51:44 +0100 Subject: [PATCH] Add tests on proximityPrecision setting --- meilisearch/tests/settings/mod.rs | 1 + .../tests/settings/proximity_settings.rs | 396 ++++++++++++++++++ 2 files changed, 397 insertions(+) create mode 100644 meilisearch/tests/settings/proximity_settings.rs diff --git a/meilisearch/tests/settings/mod.rs b/meilisearch/tests/settings/mod.rs index 70125a360..ccb4139e6 100644 --- a/meilisearch/tests/settings/mod.rs +++ b/meilisearch/tests/settings/mod.rs @@ -1,4 +1,5 @@ mod distinct; mod errors; mod get_settings; +mod proximity_settings; mod tokenizer_customization; diff --git a/meilisearch/tests/settings/proximity_settings.rs b/meilisearch/tests/settings/proximity_settings.rs new file mode 100644 index 000000000..d445adbfa --- /dev/null +++ b/meilisearch/tests/settings/proximity_settings.rs @@ -0,0 +1,396 @@ +use meili_snap::{json_string, snapshot}; +use once_cell::sync::Lazy; + +use crate::common::Server; +use crate::json; + +static DOCUMENTS: Lazy = Lazy::new(|| { + json!([ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish", + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish", + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish", + }, + ]) +}); + +#[actix_rt::test] +async fn attribute_scale_search() { + let server = Server::new().await; + let (response, code) = server.set_features(json!({"proximityPrecision": true})).await; + meili_snap::snapshot!(code, @"200 OK"); + meili_snap::snapshot!(meili_snap::json_string!(response), @r###" + { + "scoreDetails": false, + "vectorStore": false, + "metrics": false, + "exportPuffinReports": false, + "proximityPrecision": true + } + "###); + let index = server.index("test"); + + index.add_documents(DOCUMENTS.clone(), None).await; + index.wait_task(0).await; + + let (response, code) = index + .update_settings(json!({ + "proximityPrecision": "attributeScale", + "rankingRules": ["words", "typo", "proximity"], + })) + .await; + assert_eq!("202", code.as_str(), "{:?}", response); + index.wait_task(1).await; + + // the expected order is [1, 3, 2] instead of [3, 1, 2] + // because the attribute scale doesn't make the difference between 1 and 3. + index + .search(json!({"q": "the soup of day"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish" + } + ] + "###); + }) + .await; + + // the expected order is [1, 2, 3] instead of [1, 3, 2] + // because the attribute scale sees all the word in the same attribute + // and so doesn't make the difference between the documents. + index + .search(json!({"q": "many the fish"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish" + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + } + ] + "###); + }) + .await; +} + +#[actix_rt::test] +async fn attribute_scale_phrase_search() { + let server = Server::new().await; + let (response, code) = server.set_features(json!({"proximityPrecision": true})).await; + meili_snap::snapshot!(code, @"200 OK"); + meili_snap::snapshot!(meili_snap::json_string!(response), @r###" + { + "scoreDetails": false, + "vectorStore": false, + "metrics": false, + "exportPuffinReports": false, + "proximityPrecision": true + } + "###); + let index = server.index("test"); + + index.add_documents(DOCUMENTS.clone(), None).await; + index.wait_task(0).await; + + let (_response, _code) = index + .update_settings(json!({ + "proximityPrecision": "attributeScale", + "rankingRules": ["words", "typo", "proximity"], + })) + .await; + index.wait_task(1).await; + + // the expected order is [1, 3] instead of [3, 1] + // because the attribute scale doesn't make the difference between 1 and 3. + // But 2 shouldn't be returned because "the" is not in the same attribute. + index + .search(json!({"q": "\"the soup of day\""}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + } + ] + "###); + }) + .await; + + // the expected order is [1, 2, 3] instead of [1, 3] + // because the attribute scale sees all the word in the same attribute + // and so doesn't make the difference between the documents. + index + .search(json!({"q": "\"many the fish\""}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish" + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + } + ] + "###); + }) + .await; +} + +#[actix_rt::test] +async fn word_scale_set_and_reset() { + let server = Server::new().await; + let (response, code) = server.set_features(json!({"proximityPrecision": true})).await; + meili_snap::snapshot!(code, @"200 OK"); + meili_snap::snapshot!(meili_snap::json_string!(response), @r###" + { + "scoreDetails": false, + "vectorStore": false, + "metrics": false, + "exportPuffinReports": false, + "proximityPrecision": true + } + "###); + let index = server.index("test"); + + index.add_documents(DOCUMENTS.clone(), None).await; + index.wait_task(0).await; + + // Set and reset the setting ensuring the swap between the 2 settings is applied. + let (_response, _code) = index + .update_settings(json!({ + "proximityPrecision": "attributeScale", + "rankingRules": ["words", "typo", "proximity"], + })) + .await; + index.wait_task(1).await; + + let (_response, _code) = index + .update_settings(json!({ + "proximityPrecision": "wordScale", + "rankingRules": ["words", "typo", "proximity"], + })) + .await; + index.wait_task(2).await; + + // [3, 1, 2] + index + .search(json!({"q": "the soup of day"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + }, + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish" + } + ] + "###); + }) + .await; + + // [1, 3, 2] + index + .search(json!({"q": "many the fish"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish" + } + ] + "###); + }) + .await; + + // [3] + index + .search(json!({"q": "\"the soup of day\""}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + } + ] + "###); + }) + .await; + + // [1, 3] + index + .search(json!({"q": "\"many the fish\""}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + } + ] + "###); + }) + .await; +} + +#[actix_rt::test] +async fn attribute_scale_default_ranking_rules() { + let server = Server::new().await; + let (response, code) = server.set_features(json!({"proximityPrecision": true})).await; + meili_snap::snapshot!(code, @"200 OK"); + meili_snap::snapshot!(meili_snap::json_string!(response), @r###" + { + "scoreDetails": false, + "vectorStore": false, + "metrics": false, + "exportPuffinReports": false, + "proximityPrecision": true + } + "###); + let index = server.index("test"); + + index.add_documents(DOCUMENTS.clone(), None).await; + index.wait_task(0).await; + + let (response, code) = index + .update_settings(json!({ + "proximityPrecision": "attributeScale" + })) + .await; + assert_eq!("202", code.as_str(), "{:?}", response); + index.wait_task(1).await; + + // the expected order is [3, 1, 2] + index + .search(json!({"q": "the soup of day"}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + }, + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish" + } + ] + "###); + }) + .await; + + // the expected order is [1, 3, 2] instead of [1, 3] + // because the attribute scale sees all the word in the same attribute + // and so doesn't remove the document 2. + index + .search(json!({"q": "\"many the fish\""}), |response, code| { + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "a": "Soup of the day", + "b": "many the fish" + }, + { + "id": 3, + "a": "the Soup of day", + "b": "many the fish" + }, + { + "id": 2, + "a": "Soup of day", + "b": "many the lazy fish" + } + ] + "###); + }) + .await; +}