This commit is contained in:
mpostma 2021-01-01 16:59:49 +01:00
parent d1e9ded76f
commit b4d447b5cb
8 changed files with 70 additions and 238 deletions

2
Cargo.lock generated
View File

@ -1588,7 +1588,7 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]] [[package]]
name = "meilisearch-error" name = "meilisearch-error"
version = "0.17.0" version = "0.15.0"
dependencies = [ dependencies = [
"actix-http", "actix-http",
] ]

View File

@ -3,6 +3,7 @@ mod updates;
pub use search::{SearchQuery, SearchResult}; pub use search::{SearchQuery, SearchResult};
use std::collections::HashMap;
use std::fs::create_dir_all; use std::fs::create_dir_all;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
@ -10,7 +11,7 @@ use std::sync::Arc;
use milli::Index; use milli::Index;
use sha2::Digest; use sha2::Digest;
use crate::option::Opt; use crate::{option::Opt, updates::Settings};
use crate::updates::UpdateQueue; use crate::updates::UpdateQueue;
#[derive(Clone)] #[derive(Clone)]
@ -82,6 +83,39 @@ impl Data {
Ok(Data { inner }) Ok(Data { inner })
} }
pub fn settings<S: AsRef<str>>(&self, _index: S) -> anyhow::Result<Settings> {
let txn = self.indexes.env.read_txn()?;
let fields_map = self.indexes.fields_ids_map(&txn)?;
println!("fields_map: {:?}", fields_map);
let displayed_attributes = self.indexes
.displayed_fields(&txn)?
.map(|fields| {println!("{:?}", fields); fields.iter().filter_map(|f| fields_map.name(*f).map(String::from)).collect()})
.unwrap_or_else(|| vec!["*".to_string()]);
let searchable_attributes = self.indexes
.searchable_fields(&txn)?
.map(|fields| fields
.iter()
.filter_map(|f| fields_map.name(*f).map(String::from))
.collect())
.unwrap_or_else(|| vec!["*".to_string()]);
let faceted_attributes = self.indexes
.faceted_fields(&txn)?
.iter()
.filter_map(|(f, t)| Some((fields_map.name(*f)?.to_string(), t.to_string())))
.collect::<HashMap<_, _>>()
.into();
Ok(Settings {
displayed_attributes: Some(Some(displayed_attributes)),
searchable_attributes: Some(Some(searchable_attributes)),
faceted_attributes: Some(faceted_attributes),
criteria: None,
})
}
#[inline] #[inline]
pub fn http_payload_size_limit(&self) -> usize { pub fn http_payload_size_limit(&self) -> usize {
self.options.http_payload_size_limit.get_bytes() as usize self.options.http_payload_size_limit.get_bytes() as usize

View File

@ -7,7 +7,7 @@ use milli::update::{IndexDocumentsMethod, UpdateFormat};
use milli::update_store::UpdateStatus; use milli::update_store::UpdateStatus;
use super::Data; use super::Data;
use crate::updates::{UpdateMeta, UpdateResult}; use crate::updates::{UpdateMeta, UpdateResult, UpdateStatusResponse, Settings};
impl Data { impl Data {
pub async fn add_documents<B, E, S>( pub async fn add_documents<B, E, S>(
@ -16,7 +16,7 @@ impl Data {
method: IndexDocumentsMethod, method: IndexDocumentsMethod,
format: UpdateFormat, format: UpdateFormat,
mut stream: impl futures::Stream<Item=Result<B, E>> + Unpin, mut stream: impl futures::Stream<Item=Result<B, E>> + Unpin,
) -> anyhow::Result<UpdateStatus<UpdateMeta, String, String>> ) -> anyhow::Result<UpdateStatusResponse>
where where
B: Deref<Target = [u8]>, B: Deref<Target = [u8]>,
E: std::error::Error + Send + Sync + 'static, E: std::error::Error + Send + Sync + 'static,
@ -45,6 +45,16 @@ impl Data {
Ok(update.into()) Ok(update.into())
} }
pub async fn update_settings<S: AsRef<str>>(
&self,
_index: S,
settings: Settings
) -> anyhow::Result<UpdateStatusResponse> {
let meta = UpdateMeta::Settings(settings);
let queue = self.update_queue.clone();
let update = tokio::task::spawn_blocking(move || queue.register_update(meta, &[])).await??;
Ok(update.into())
}
#[inline] #[inline]
pub fn get_update_status(&self, _index: &str, uid: u64) -> anyhow::Result<Option<UpdateStatus<UpdateMeta, UpdateResult, String>>> { pub fn get_update_status(&self, _index: &str, uid: u64) -> anyhow::Result<Option<UpdateStatus<UpdateMeta, UpdateResult, String>>> {

View File

@ -46,7 +46,7 @@ pub fn create_app(
.configure(routes::document::services) .configure(routes::document::services)
.configure(routes::index::services) .configure(routes::index::services)
.configure(routes::search::services) .configure(routes::search::services)
.configure(routes::setting::services) .configure(routes::settings::services)
.configure(routes::stop_words::services) .configure(routes::stop_words::services)
.configure(routes::synonym::services) .configure(routes::synonym::services)
.configure(routes::health::services) .configure(routes::health::services)

View File

@ -6,7 +6,7 @@ pub mod health;
pub mod index; pub mod index;
pub mod key; pub mod key;
pub mod search; pub mod search;
pub mod setting; pub mod settings;
pub mod stats; pub mod stats;
pub mod stop_words; pub mod stop_words;
pub mod synonym; pub mod synonym;

View File

@ -1,226 +0,0 @@
use std::collections::BTreeSet;
use actix_web::{delete, get, post};
use actix_web::{web, HttpResponse};
use crate::Data;
use crate::error::ResponseError;
use crate::helpers::Authentication;
use crate::updates::Settings;
pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(update_all)
.service(get_all)
.service(delete_all)
.service(get_rules)
.service(update_rules)
.service(delete_rules)
.service(get_distinct)
.service(update_distinct)
.service(delete_distinct)
.service(get_searchable)
.service(update_searchable)
.service(delete_searchable)
.service(get_displayed)
.service(update_displayed)
.service(delete_displayed)
.service(get_attributes_for_faceting)
.service(delete_attributes_for_faceting)
.service(update_attributes_for_faceting);
}
#[post("/indexes/{index_uid}/settings", wrap = "Authentication::Private")]
async fn update_all(
_data: web::Data<Data>,
_path: web::Path<String>,
_body: web::Json<Settings>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[get("/indexes/{index_uid}/settings", wrap = "Authentication::Private")]
async fn get_all(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[delete("/indexes/{index_uid}/settings", wrap = "Authentication::Private")]
async fn delete_all(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[get(
"/indexes/{index_uid}/settings/ranking-rules",
wrap = "Authentication::Private"
)]
async fn get_rules(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[post(
"/indexes/{index_uid}/settings/ranking-rules",
wrap = "Authentication::Private"
)]
async fn update_rules(
_data: web::Data<Data>,
_path: web::Path<String>,
_body: web::Json<Option<Vec<String>>>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[delete(
"/indexes/{index_uid}/settings/ranking-rules",
wrap = "Authentication::Private"
)]
async fn delete_rules(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[get(
"/indexes/{index_uid}/settings/distinct-attribute",
wrap = "Authentication::Private"
)]
async fn get_distinct(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[post(
"/indexes/{index_uid}/settings/distinct-attribute",
wrap = "Authentication::Private"
)]
async fn update_distinct(
_data: web::Data<Data>,
_path: web::Path<String>,
_body: web::Json<Option<String>>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[delete(
"/indexes/{index_uid}/settings/distinct-attribute",
wrap = "Authentication::Private"
)]
async fn delete_distinct(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[get(
"/indexes/{index_uid}/settings/searchable-attributes",
wrap = "Authentication::Private"
)]
async fn get_searchable(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[post(
"/indexes/{index_uid}/settings/searchable-attributes",
wrap = "Authentication::Private"
)]
async fn update_searchable(
_data: web::Data<Data>,
_path: web::Path<String>,
_body: web::Json<Option<Vec<String>>>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[delete(
"/indexes/{index_uid}/settings/searchable-attributes",
wrap = "Authentication::Private"
)]
async fn delete_searchable(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[get(
"/indexes/{index_uid}/settings/displayed-attributes",
wrap = "Authentication::Private"
)]
async fn get_displayed(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[post(
"/indexes/{index_uid}/settings/displayed-attributes",
wrap = "Authentication::Private"
)]
async fn update_displayed(
_data: web::Data<Data>,
_path: web::Path<String>,
_body: web::Json<Option<BTreeSet<String>>>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[delete(
"/indexes/{index_uid}/settings/displayed-attributes",
wrap = "Authentication::Private"
)]
async fn delete_displayed(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[get(
"/indexes/{index_uid}/settings/attributes-for-faceting",
wrap = "Authentication::Private"
)]
async fn get_attributes_for_faceting(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[post(
"/indexes/{index_uid}/settings/attributes-for-faceting",
wrap = "Authentication::Private"
)]
async fn update_attributes_for_faceting(
_data: web::Data<Data>,
_path: web::Path<String>,
_body: web::Json<Option<Vec<String>>>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}
#[delete(
"/indexes/{index_uid}/settings/attributes-for-faceting",
wrap = "Authentication::Private"
)]
async fn delete_attributes_for_faceting(
_data: web::Data<Data>,
_path: web::Path<String>,
) -> Result<HttpResponse, ResponseError> {
todo!()
}

View File

@ -6,6 +6,7 @@ use std::io;
use std::sync::Arc; use std::sync::Arc;
use std::ops::Deref; use std::ops::Deref;
use std::fs::create_dir_all; use std::fs::create_dir_all;
use std::collections::HashMap;
use anyhow::Result; use anyhow::Result;
use byte_unit::Byte; use byte_unit::Byte;
@ -21,6 +22,8 @@ use structopt::StructOpt;
use crate::option::Opt; use crate::option::Opt;
pub type UpdateStatusResponse = UpdateStatus<UpdateMeta, UpdateResult, String>;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum UpdateMeta { pub enum UpdateMeta {
@ -231,7 +234,8 @@ impl UpdateHandler {
// We transpose the settings JSON struct into a real setting update. // We transpose the settings JSON struct into a real setting update.
if let Some(ref facet_types) = settings.faceted_attributes { if let Some(ref facet_types) = settings.faceted_attributes {
builder.set_faceted_fields(facet_types.clone()); let facet_types = facet_types.clone().unwrap_or_else(|| HashMap::new());
builder.set_faceted_fields(facet_types);
} }
// We transpose the settings JSON struct into a real setting update. // We transpose the settings JSON struct into a real setting update.
@ -245,7 +249,7 @@ impl UpdateHandler {
let result = builder.execute(|indexing_step, update_id| info!("update {}: {:?}", update_id, indexing_step)); let result = builder.execute(|indexing_step, update_id| info!("update {}: {:?}", update_id, indexing_step));
match result { match result {
Ok(_count) => wtxn Ok(()) => wtxn
.commit() .commit()
.and(Ok(UpdateResult::Other)) .and(Ok(UpdateResult::Other))
.map_err(Into::into), .map_err(Into::into),
@ -316,7 +320,7 @@ impl UpdateQueue {
} }
#[inline] #[inline]
pub fn get_update_status(&self, update_id: u64) -> Result<Option<UpdateStatus<UpdateMeta, UpdateResult, String>>> { pub fn get_update_status(&self, update_id: u64) -> Result<Option<UpdateStatusResponse>> {
Ok(self.inner.meta(update_id)?) Ok(self.inner.meta(update_id)?)
} }
} }

View File

@ -11,7 +11,7 @@ where T: Deserialize<'de>,
Deserialize::deserialize(deserializer).map(Some) Deserialize::deserialize(deserializer).map(Some)
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Settings { pub struct Settings {
@ -30,7 +30,7 @@ pub struct Settings {
pub searchable_attributes: Option<Option<Vec<String>>>, pub searchable_attributes: Option<Option<Vec<String>>>,
#[serde(default)] #[serde(default)]
pub faceted_attributes: Option<HashMap<String, String>>, pub faceted_attributes: Option<Option<HashMap<String, String>>>,
#[serde( #[serde(
default, default,
@ -40,6 +40,17 @@ pub struct Settings {
pub criteria: Option<Option<Vec<String>>>, pub criteria: Option<Option<Vec<String>>>,
} }
impl Settings {
pub fn cleared() -> Self {
Self {
displayed_attributes: Some(None),
searchable_attributes: Some(None),
faceted_attributes: Some(None),
criteria: Some(None),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
@ -48,4 +59,3 @@ pub struct Facets {
pub level_group_size: Option<NonZeroUsize>, pub level_group_size: Option<NonZeroUsize>,
pub min_level_size: Option<NonZeroUsize>, pub min_level_size: Option<NonZeroUsize>,
} }