mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-23 02:27:40 +08:00
Merge #124
124: enable distinct r=MarinPostma a=MarinPostma Co-authored-by: mpostma <postma.marin@protonmail.com> Co-authored-by: Marin Postma <postma.marin@protonmail.com>
This commit is contained in:
commit
63d443deb8
1421
meilisearch-http/Cargo.lock → Cargo.lock
generated
1421
meilisearch-http/Cargo.lock → Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -84,6 +84,7 @@ version = "0.18.1"
|
|||||||
actix-rt = "2.1.0"
|
actix-rt = "2.1.0"
|
||||||
assert-json-diff = { branch = "master", git = "https://github.com/qdequele/assert-json-diff" }
|
assert-json-diff = { branch = "master", git = "https://github.com/qdequele/assert-json-diff" }
|
||||||
mockall = "0.9.1"
|
mockall = "0.9.1"
|
||||||
|
paste = "1.0.5"
|
||||||
serde_url_params = "0.2.0"
|
serde_url_params = "0.2.0"
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
urlencoding = "1.1.1"
|
urlencoding = "1.1.1"
|
||||||
|
@ -59,6 +59,9 @@ impl Index {
|
|||||||
})
|
})
|
||||||
.transpose()?
|
.transpose()?
|
||||||
.unwrap_or_else(BTreeSet::new);
|
.unwrap_or_else(BTreeSet::new);
|
||||||
|
let distinct_attribute = self
|
||||||
|
.distinct_attribute(&txn)?
|
||||||
|
.map(String::from);
|
||||||
|
|
||||||
Ok(Settings {
|
Ok(Settings {
|
||||||
displayed_attributes: Some(Some(displayed_attributes)),
|
displayed_attributes: Some(Some(displayed_attributes)),
|
||||||
@ -66,6 +69,7 @@ impl Index {
|
|||||||
attributes_for_faceting: Some(Some(faceted_attributes)),
|
attributes_for_faceting: Some(Some(faceted_attributes)),
|
||||||
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_attribute),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,13 +43,18 @@ pub struct Settings {
|
|||||||
skip_serializing_if = "Option::is_none"
|
skip_serializing_if = "Option::is_none"
|
||||||
)]
|
)]
|
||||||
pub ranking_rules: Option<Option<Vec<String>>>,
|
pub ranking_rules: Option<Option<Vec<String>>>,
|
||||||
|
|
||||||
#[serde(
|
#[serde(
|
||||||
default,
|
default,
|
||||||
deserialize_with = "deserialize_some",
|
deserialize_with = "deserialize_some",
|
||||||
skip_serializing_if = "Option::is_none"
|
skip_serializing_if = "Option::is_none"
|
||||||
)]
|
)]
|
||||||
pub stop_words: Option<Option<BTreeSet<String>>>,
|
pub stop_words: Option<Option<BTreeSet<String>>>,
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
deserialize_with = "deserialize_some",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
pub distinct_attribute: Option<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
@ -60,6 +65,7 @@ impl Settings {
|
|||||||
attributes_for_faceting: Some(None),
|
attributes_for_faceting: Some(None),
|
||||||
ranking_rules: Some(None),
|
ranking_rules: Some(None),
|
||||||
stop_words: Some(None),
|
stop_words: Some(None),
|
||||||
|
distinct_attribute: Some(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,7 +151,6 @@ impl Index {
|
|||||||
let mut wtxn = self.write_txn()?;
|
let mut wtxn = self.write_txn()?;
|
||||||
let mut builder = update_builder.settings(&mut wtxn, self);
|
let mut builder = update_builder.settings(&mut wtxn, self);
|
||||||
|
|
||||||
// We transpose the settings JSON struct into a real setting update.
|
|
||||||
if let Some(ref names) = settings.searchable_attributes {
|
if let Some(ref names) = settings.searchable_attributes {
|
||||||
match names {
|
match names {
|
||||||
Some(names) => builder.set_searchable_fields(names.clone()),
|
Some(names) => builder.set_searchable_fields(names.clone()),
|
||||||
@ -153,7 +158,6 @@ impl Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We transpose the settings JSON struct into a real setting update.
|
|
||||||
if let Some(ref names) = settings.displayed_attributes {
|
if let Some(ref names) = settings.displayed_attributes {
|
||||||
match names {
|
match names {
|
||||||
Some(names) => builder.set_displayed_fields(names.clone()),
|
Some(names) => builder.set_displayed_fields(names.clone()),
|
||||||
@ -161,13 +165,11 @@ impl Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We transpose the settings JSON struct into a real setting update.
|
|
||||||
if let Some(ref facet_types) = settings.attributes_for_faceting {
|
if let Some(ref facet_types) = settings.attributes_for_faceting {
|
||||||
let facet_types = facet_types.clone().unwrap_or_else(HashMap::new);
|
let facet_types = facet_types.clone().unwrap_or_else(HashMap::new);
|
||||||
builder.set_faceted_fields(facet_types);
|
builder.set_faceted_fields(facet_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We transpose the settings JSON struct into a real setting update.
|
|
||||||
if let Some(ref criteria) = settings.ranking_rules {
|
if let Some(ref criteria) = settings.ranking_rules {
|
||||||
match criteria {
|
match criteria {
|
||||||
Some(criteria) => builder.set_criteria(criteria.clone()),
|
Some(criteria) => builder.set_criteria(criteria.clone()),
|
||||||
@ -175,7 +177,6 @@ impl Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We transpose the settings JSON struct into a real setting update.
|
|
||||||
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()),
|
||||||
@ -183,6 +184,13 @@ impl Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref distinct_attribute) = settings.distinct_attribute {
|
||||||
|
match distinct_attribute {
|
||||||
|
Some(attr) => builder.set_distinct_attribute(attr.clone()),
|
||||||
|
None => builder.reset_distinct_attribute(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let result = builder
|
let result = builder
|
||||||
.execute(|indexing_step, update_id| info!("update {}: {:?}", update_id, indexing_step));
|
.execute(|indexing_step, update_id| info!("update {}: {:?}", update_id, indexing_step));
|
||||||
|
|
||||||
|
@ -97,11 +97,11 @@ make_setting_route!(
|
|||||||
stop_words
|
stop_words
|
||||||
);
|
);
|
||||||
|
|
||||||
//make_setting_route!(
|
make_setting_route!(
|
||||||
//"/indexes/{index_uid}/settings/distinct-attribute",
|
"/indexes/{index_uid}/settings/distinct-attribute",
|
||||||
//String,
|
String,
|
||||||
//distinct_attribute
|
distinct_attribute
|
||||||
//);
|
);
|
||||||
|
|
||||||
//make_setting_route!(
|
//make_setting_route!(
|
||||||
//"/indexes/{index_uid}/settings/ranking-rules",
|
//"/indexes/{index_uid}/settings/ranking-rules",
|
||||||
@ -129,6 +129,7 @@ create_services!(
|
|||||||
attributes_for_faceting,
|
attributes_for_faceting,
|
||||||
displayed_attributes,
|
displayed_attributes,
|
||||||
searchable_attributes,
|
searchable_attributes,
|
||||||
|
distinct_attribute,
|
||||||
stop_words
|
stop_words
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,16 +1,34 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
|
use paste::paste;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
use super::service::Service;
|
use super::service::Service;
|
||||||
|
|
||||||
|
macro_rules! make_settings_test_routes {
|
||||||
|
($($name:ident),+) => {
|
||||||
|
$(paste! {
|
||||||
|
pub async fn [<update_$name>](&self, value: Value) -> (Value, StatusCode) {
|
||||||
|
let url = format!("/indexes/{}/settings/{}", self.uid, stringify!($name).replace("_", "-"));
|
||||||
|
self.service.post(url, value).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn [<get_$name>](&self) -> (Value, StatusCode) {
|
||||||
|
let url = format!("/indexes/{}/settings/{}", self.uid, stringify!($name).replace("_", "-"));
|
||||||
|
self.service.get(url).await
|
||||||
|
}
|
||||||
|
})*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Index<'a> {
|
pub struct Index<'a> {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
pub service: &'a Service,
|
pub service: &'a Service,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl Index<'_> {
|
impl Index<'_> {
|
||||||
pub async fn get(&self) -> (Value, StatusCode) {
|
pub async fn get(&self) -> (Value, StatusCode) {
|
||||||
let url = format!("/indexes/{}", self.uid);
|
let url = format!("/indexes/{}", self.uid);
|
||||||
@ -166,8 +184,13 @@ impl Index<'_> {
|
|||||||
let url = format!("/indexes/{}/stats", self.uid);
|
let url = format!("/indexes/{}/stats", self.uid);
|
||||||
self.service.get(url).await
|
self.service.get(url).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_settings_test_routes!(
|
||||||
|
distinct_attribute
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct GetDocumentOptions;
|
pub struct GetDocumentOptions;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
44
meilisearch-http/tests/settings/distinct.rs
Normal file
44
meilisearch-http/tests/settings/distinct.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use crate::common::Server;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn set_and_reset_distinct_attribute() {
|
||||||
|
let server = Server::new().await;
|
||||||
|
let index = server.index("test");
|
||||||
|
|
||||||
|
let (_response, _code) = index.update_settings(json!({ "distinctAttribute": "test"})).await;
|
||||||
|
index.wait_update_id(0).await;
|
||||||
|
|
||||||
|
let (response, _) = index.settings().await;
|
||||||
|
|
||||||
|
assert_eq!(response["distinctAttribute"], "test");
|
||||||
|
|
||||||
|
index.update_settings(json!({ "distinctAttribute": null })).await;
|
||||||
|
|
||||||
|
index.wait_update_id(1).await;
|
||||||
|
|
||||||
|
let (response, _) = index.settings().await;
|
||||||
|
|
||||||
|
assert_eq!(response["distinctAttribute"], json!(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn set_and_reset_distinct_attribute_with_dedicated_route() {
|
||||||
|
let server = Server::new().await;
|
||||||
|
let index = server.index("test");
|
||||||
|
|
||||||
|
let (_response, _code) = index.update_distinct_attribute(json!("test")).await;
|
||||||
|
index.wait_update_id(0).await;
|
||||||
|
|
||||||
|
let (response, _) = index.get_distinct_attribute().await;
|
||||||
|
|
||||||
|
assert_eq!(response, "test");
|
||||||
|
|
||||||
|
index.update_distinct_attribute(json!(null)).await;
|
||||||
|
|
||||||
|
index.wait_update_id(1).await;
|
||||||
|
|
||||||
|
let (response, _) = index.get_distinct_attribute().await;
|
||||||
|
|
||||||
|
assert_eq!(response, json!(null));
|
||||||
|
}
|
@ -16,10 +16,11 @@ 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(), 5);
|
assert_eq!(settings.keys().len(), 6);
|
||||||
assert_eq!(settings["displayedAttributes"], json!(["*"]));
|
assert_eq!(settings["displayedAttributes"], json!(["*"]));
|
||||||
assert_eq!(settings["searchableAttributes"], json!(["*"]));
|
assert_eq!(settings["searchableAttributes"], json!(["*"]));
|
||||||
assert_eq!(settings["attributesForFaceting"], json!({}));
|
assert_eq!(settings["attributesForFaceting"], json!({}));
|
||||||
|
assert_eq!(settings["distinctAttribute"], json!(null));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
settings["rankingRules"],
|
settings["rankingRules"],
|
||||||
json!([
|
json!([
|
||||||
|
@ -1 +1,2 @@
|
|||||||
mod get_settings;
|
mod get_settings;
|
||||||
|
mod distinct;
|
||||||
|
Loading…
Reference in New Issue
Block a user