diff --git a/meilisearch-http/src/routes/search.rs b/meilisearch-http/src/routes/search.rs index 0d698eafb..654d50fcf 100644 --- a/meilisearch-http/src/routes/search.rs +++ b/meilisearch-http/src/routes/search.rs @@ -8,7 +8,7 @@ use serde::Deserialize; use serde_json::Value; use crate::error::{Error, FacetCountError, ResponseError}; -use crate::helpers::meilisearch::IndexSearchExt; +use crate::helpers::meilisearch::{IndexSearchExt, SearchResult}; use crate::helpers::Authentication; use crate::routes::IndexParam; use crate::Data; @@ -36,129 +36,134 @@ struct SearchQuery { facets_distribution: Option, } +impl SearchQuery { + fn search(&self, index_uid: &str, data: web::Data) -> Result { + let index = data + .db + .open_index(index_uid) + .ok_or(Error::index_not_found(index_uid))?; + + let reader = data.db.main_read_txn()?; + let schema = index + .main + .schema(&reader)? + .ok_or(Error::internal("Impossible to retrieve the schema"))?; + + let mut search_builder = index.new_search(self.q.clone()); + + if let Some(offset) = self.offset { + search_builder.offset(offset); + } + if let Some(limit) = self.limit { + search_builder.limit(limit); + } + + let available_attributes = schema.displayed_name(); + let mut restricted_attributes: HashSet<&str>; + match &self.attributes_to_retrieve { + Some(attributes_to_retrieve) => { + let attributes_to_retrieve: HashSet<&str> = attributes_to_retrieve.split(',').collect(); + if attributes_to_retrieve.contains("*") { + restricted_attributes = available_attributes.clone(); + } else { + restricted_attributes = HashSet::new(); + for attr in attributes_to_retrieve { + if available_attributes.contains(attr) { + restricted_attributes.insert(attr); + search_builder.add_retrievable_field(attr.to_string()); + } else { + warn!("The attributes {:?} present in attributesToCrop parameter doesn't exist", attr); + } + } + } + }, + None => { + restricted_attributes = available_attributes.clone(); + } + } + + if let Some(ref facet_filters) = self.facet_filters { + let attrs = index.main.attributes_for_faceting(&reader)?.unwrap_or_default(); + search_builder.add_facet_filters(FacetFilter::from_str(facet_filters, &schema, &attrs)?); + } + + if let Some(facets) = &self.facets_distribution { + match index.main.attributes_for_faceting(&reader)? { + Some(ref attrs) => { + let field_ids = prepare_facet_list(&facets, &schema, attrs)?; + search_builder.add_facets(field_ids); + }, + None => return Err(FacetCountError::NoFacetSet.into()), + } + } + + if let Some(attributes_to_crop) = &self.attributes_to_crop { + let default_length = self.crop_length.unwrap_or(200); + let mut final_attributes: HashMap = HashMap::new(); + + for attribute in attributes_to_crop.split(',') { + let mut attribute = attribute.split(':'); + let attr = attribute.next(); + let length = attribute.next().and_then(|s| s.parse().ok()).unwrap_or(default_length); + match attr { + Some("*") => { + for attr in &restricted_attributes { + final_attributes.insert(attr.to_string(), length); + } + }, + Some(attr) => { + if available_attributes.contains(attr) { + final_attributes.insert(attr.to_string(), length); + } else { + warn!("The attributes {:?} present in attributesToCrop parameter doesn't exist", attr); + } + }, + None => (), + } + } + + search_builder.attributes_to_crop(final_attributes); + } + + if let Some(attributes_to_highlight) = &self.attributes_to_highlight { + let mut final_attributes: HashSet = HashSet::new(); + for attribute in attributes_to_highlight.split(',') { + if attribute == "*" { + for attr in &restricted_attributes { + final_attributes.insert(attr.to_string()); + } + } else { + if available_attributes.contains(attribute) { + final_attributes.insert(attribute.to_string()); + } else { + warn!("The attributes {:?} present in attributesToHighlight parameter doesn't exist", attribute); + } + } + } + + search_builder.attributes_to_highlight(final_attributes); + } + + if let Some(filters) = &self.filters { + search_builder.filters(filters.to_string()); + } + + if let Some(matches) = self.matches { + if matches { + search_builder.get_matches(); + } + } + search_builder.search(&reader) + } +} + #[get("/indexes/{index_uid}/search", wrap = "Authentication::Public")] async fn search_with_url_query( data: web::Data, path: web::Path, params: web::Query, ) -> Result { - let index = data - .db - .open_index(&path.index_uid) - .ok_or(Error::index_not_found(&path.index_uid))?; - - let reader = data.db.main_read_txn()?; - let schema = index - .main - .schema(&reader)? - .ok_or(Error::internal("Impossible to retrieve the schema"))?; - - let mut search_builder = index.new_search(params.q.clone()); - - if let Some(offset) = params.offset { - search_builder.offset(offset); - } - if let Some(limit) = params.limit { - search_builder.limit(limit); - } - - let available_attributes = schema.displayed_name(); - let mut restricted_attributes: HashSet<&str>; - match ¶ms.attributes_to_retrieve { - Some(attributes_to_retrieve) => { - let attributes_to_retrieve: HashSet<&str> = attributes_to_retrieve.split(',').collect(); - if attributes_to_retrieve.contains("*") { - restricted_attributes = available_attributes.clone(); - } else { - restricted_attributes = HashSet::new(); - for attr in attributes_to_retrieve { - if available_attributes.contains(attr) { - restricted_attributes.insert(attr); - search_builder.add_retrievable_field(attr.to_string()); - } else { - warn!("The attributes {:?} present in attributesToCrop parameter doesn't exist", attr); - } - } - } - }, - None => { - restricted_attributes = available_attributes.clone(); - } - } - - if let Some(ref facet_filters) = params.facet_filters { - let attrs = index.main.attributes_for_faceting(&reader)?.unwrap_or_default(); - search_builder.add_facet_filters(FacetFilter::from_str(facet_filters, &schema, &attrs)?); - } - - if let Some(facets) = ¶ms.facets_distribution { - match index.main.attributes_for_faceting(&reader)? { - Some(ref attrs) => { - let field_ids = prepare_facet_list(&facets, &schema, attrs)?; - search_builder.add_facets(field_ids); - }, - None => return Err(FacetCountError::NoFacetSet.into()), - } - } - - if let Some(attributes_to_crop) = ¶ms.attributes_to_crop { - let default_length = params.crop_length.unwrap_or(200); - let mut final_attributes: HashMap = HashMap::new(); - - for attribute in attributes_to_crop.split(',') { - let mut attribute = attribute.split(':'); - let attr = attribute.next(); - let length = attribute.next().and_then(|s| s.parse().ok()).unwrap_or(default_length); - match attr { - Some("*") => { - for attr in &restricted_attributes { - final_attributes.insert(attr.to_string(), length); - } - }, - Some(attr) => { - if available_attributes.contains(attr) { - final_attributes.insert(attr.to_string(), length); - } else { - warn!("The attributes {:?} present in attributesToCrop parameter doesn't exist", attr); - } - }, - None => (), - } - } - - search_builder.attributes_to_crop(final_attributes); - } - - if let Some(attributes_to_highlight) = ¶ms.attributes_to_highlight { - let mut final_attributes: HashSet = HashSet::new(); - for attribute in attributes_to_highlight.split(',') { - if attribute == "*" { - for attr in &restricted_attributes { - final_attributes.insert(attr.to_string()); - } - } else { - if available_attributes.contains(attribute) { - final_attributes.insert(attribute.to_string()); - } else { - warn!("The attributes {:?} present in attributesToHighlight parameter doesn't exist", attribute); - } - } - } - - search_builder.attributes_to_highlight(final_attributes); - } - - if let Some(filters) = ¶ms.filters { - search_builder.filters(filters.to_string()); - } - - if let Some(matches) = params.matches { - if matches { - search_builder.get_matches(); - } - } - let search_result = search_builder.search(&reader)?; - + let search_result = params.search(&path.index_uid, data)?; Ok(HttpResponse::Ok().json(search_result)) }