mirror of
				https://github.com/meilisearch/meilisearch.git
				synced 2025-10-30 23:46:28 +00:00 
			
		
		
		
	Move the sortFacetValuesBy in the faceting settings
This commit is contained in:
		
				
					committed by
					
						 Clément Renault
						Clément Renault
					
				
			
			
				
	
			
			
			
						parent
						
							d9fea0143f
						
					
				
				
					commit
					9917bf046a
				
			| @@ -26,7 +26,8 @@ use crate::readable_slices::ReadableSlices; | ||||
| use crate::{ | ||||
|     default_criteria, CboRoaringBitmapCodec, Criterion, DocumentId, ExternalDocumentsIds, | ||||
|     FacetDistribution, FieldDistribution, FieldId, FieldIdWordCountCodec, GeoPoint, ObkvCodec, | ||||
|     Result, RoaringBitmapCodec, RoaringBitmapLenCodec, Search, U8StrStrCodec, BEU16, BEU32, | ||||
|     OrderBy, Result, RoaringBitmapCodec, RoaringBitmapLenCodec, Search, U8StrStrCodec, BEU16, | ||||
|     BEU32, | ||||
| }; | ||||
|  | ||||
| /// The HNSW data-structure that we serialize, fill and search in. | ||||
| @@ -71,6 +72,7 @@ pub mod main_key { | ||||
|     pub const EXACT_WORDS: &str = "exact-words"; | ||||
|     pub const EXACT_ATTRIBUTES: &str = "exact-attributes"; | ||||
|     pub const MAX_VALUES_PER_FACET: &str = "max-values-per-facet"; | ||||
|     pub const SORT_FACET_VALUES_BY: &str = "sort-facet-values-by"; | ||||
|     pub const PAGINATION_MAX_TOTAL_HITS: &str = "pagination-max-total-hits"; | ||||
| } | ||||
|  | ||||
| @@ -1298,6 +1300,31 @@ impl Index { | ||||
|         self.main.delete::<_, Str>(txn, main_key::MAX_VALUES_PER_FACET) | ||||
|     } | ||||
|  | ||||
|     pub fn sort_facet_values_by(&self, txn: &RoTxn) -> heed::Result<HashMap<String, OrderBy>> { | ||||
|         let mut orders = self | ||||
|             .main | ||||
|             .get::<_, Str, SerdeJson<HashMap<String, OrderBy>>>( | ||||
|                 txn, | ||||
|                 main_key::SORT_FACET_VALUES_BY, | ||||
|             )? | ||||
|             .unwrap_or_default(); | ||||
|         // Insert the default ordering if it is not already overwritten by the user. | ||||
|         orders.entry("*".to_string()).or_insert(OrderBy::Lexicographic); | ||||
|         Ok(orders) | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn put_sort_facet_values_by( | ||||
|         &self, | ||||
|         txn: &mut RwTxn, | ||||
|         val: &HashMap<String, OrderBy>, | ||||
|     ) -> heed::Result<()> { | ||||
|         self.main.put::<_, Str, SerdeJson<_>>(txn, main_key::SORT_FACET_VALUES_BY, &val) | ||||
|     } | ||||
|  | ||||
|     pub(crate) fn delete_sort_facet_values_by(&self, txn: &mut RwTxn) -> heed::Result<bool> { | ||||
|         self.main.delete::<_, Str>(txn, main_key::SORT_FACET_VALUES_BY) | ||||
|     } | ||||
|  | ||||
|     pub fn pagination_max_total_hits(&self, txn: &RoTxn) -> heed::Result<Option<usize>> { | ||||
|         self.main.get::<_, Str, OwnedType<usize>>(txn, main_key::PAGINATION_MAX_TOTAL_HITS) | ||||
|     } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| use std::collections::{BTreeMap, HashSet}; | ||||
| use std::collections::{BTreeMap, HashMap, HashSet}; | ||||
| use std::ops::ControlFlow; | ||||
| use std::{fmt, mem}; | ||||
|  | ||||
| @@ -6,6 +6,7 @@ use heed::types::ByteSlice; | ||||
| use heed::BytesDecode; | ||||
| use indexmap::IndexMap; | ||||
| use roaring::RoaringBitmap; | ||||
| use serde::{Deserialize, Serialize}; | ||||
|  | ||||
| use crate::error::UserError; | ||||
| use crate::facet::FacetType; | ||||
| @@ -27,7 +28,7 @@ pub const DEFAULT_VALUES_PER_FACET: usize = 100; | ||||
| const CANDIDATES_THRESHOLD: u64 = 3000; | ||||
|  | ||||
| /// How should we fetch the facets? | ||||
| #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||||
| #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] | ||||
| pub enum OrderBy { | ||||
|     /// By lexicographic order... | ||||
|     #[default] | ||||
| @@ -37,10 +38,10 @@ pub enum OrderBy { | ||||
| } | ||||
|  | ||||
| pub struct FacetDistribution<'a> { | ||||
|     facets: Option<HashSet<String>>, | ||||
|     facets: Option<HashMap<String, OrderBy>>, | ||||
|     candidates: Option<RoaringBitmap>, | ||||
|     max_values_per_facet: usize, | ||||
|     order_by: OrderBy, | ||||
|     default_order_by: OrderBy, | ||||
|     rtxn: &'a heed::RoTxn<'a>, | ||||
|     index: &'a Index, | ||||
| } | ||||
| @@ -51,14 +52,22 @@ impl<'a> FacetDistribution<'a> { | ||||
|             facets: None, | ||||
|             candidates: None, | ||||
|             max_values_per_facet: DEFAULT_VALUES_PER_FACET, | ||||
|             order_by: OrderBy::default(), | ||||
|             default_order_by: OrderBy::default(), | ||||
|             rtxn, | ||||
|             index, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn facets<I: IntoIterator<Item = A>, A: AsRef<str>>(&mut self, names: I) -> &mut Self { | ||||
|         self.facets = Some(names.into_iter().map(|s| s.as_ref().to_string()).collect()); | ||||
|     pub fn facets<I: IntoIterator<Item = (A, OrderBy)>, A: AsRef<str>>( | ||||
|         &mut self, | ||||
|         names_ordered_by: I, | ||||
|     ) -> &mut Self { | ||||
|         self.facets = Some( | ||||
|             names_ordered_by | ||||
|                 .into_iter() | ||||
|                 .map(|(name, order_by)| (name.as_ref().to_string(), order_by)) | ||||
|                 .collect(), | ||||
|         ); | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -67,8 +76,8 @@ impl<'a> FacetDistribution<'a> { | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn order_by(&mut self, order_by: OrderBy) -> &mut Self { | ||||
|         self.order_by = order_by; | ||||
|     pub fn default_order_by(&mut self, order_by: OrderBy) -> &mut Self { | ||||
|         self.default_order_by = order_by; | ||||
|         self | ||||
|     } | ||||
|  | ||||
| @@ -220,11 +229,15 @@ impl<'a> FacetDistribution<'a> { | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fn facet_values(&self, field_id: FieldId) -> heed::Result<IndexMap<String, u64>> { | ||||
|     fn facet_values( | ||||
|         &self, | ||||
|         field_id: FieldId, | ||||
|         order_by: OrderBy, | ||||
|     ) -> heed::Result<IndexMap<String, u64>> { | ||||
|         use FacetType::{Number, String}; | ||||
|  | ||||
|         let mut distribution = IndexMap::new(); | ||||
|         match (self.order_by, &self.candidates) { | ||||
|         match (order_by, &self.candidates) { | ||||
|             (OrderBy::Lexicographic, Some(cnd)) if cnd.len() <= CANDIDATES_THRESHOLD => { | ||||
|                 // Classic search, candidates were specified, we must return facet values only related | ||||
|                 // to those candidates. We also enter here for facet strings for performance reasons. | ||||
| @@ -245,13 +258,13 @@ impl<'a> FacetDistribution<'a> { | ||||
|                 self.facet_numbers_distribution_from_facet_levels( | ||||
|                     field_id, | ||||
|                     candidates, | ||||
|                     self.order_by, | ||||
|                     order_by, | ||||
|                     &mut distribution, | ||||
|                 )?; | ||||
|                 self.facet_strings_distribution_from_facet_levels( | ||||
|                     field_id, | ||||
|                     candidates, | ||||
|                     self.order_by, | ||||
|                     order_by, | ||||
|                     &mut distribution, | ||||
|                 )?; | ||||
|             } | ||||
| @@ -273,6 +286,7 @@ impl<'a> FacetDistribution<'a> { | ||||
|             Some(facets) => { | ||||
|                 let invalid_fields: HashSet<_> = facets | ||||
|                     .iter() | ||||
|                     .map(|(name, _)| name) | ||||
|                     .filter(|facet| !crate::is_faceted(facet, &filterable_fields)) | ||||
|                     .collect(); | ||||
|                 if !invalid_fields.is_empty() { | ||||
| @@ -282,7 +296,7 @@ impl<'a> FacetDistribution<'a> { | ||||
|                     } | ||||
|                     .into()); | ||||
|                 } else { | ||||
|                     facets.clone() | ||||
|                     facets.into_iter().map(|(name, _)| name).cloned().collect() | ||||
|                 } | ||||
|             } | ||||
|             None => filterable_fields, | ||||
| @@ -327,6 +341,7 @@ impl<'a> FacetDistribution<'a> { | ||||
|             Some(ref facets) => { | ||||
|                 let invalid_fields: HashSet<_> = facets | ||||
|                     .iter() | ||||
|                     .map(|(name, _)| name) | ||||
|                     .filter(|facet| !crate::is_faceted(facet, &filterable_fields)) | ||||
|                     .collect(); | ||||
|                 if !invalid_fields.is_empty() { | ||||
| @@ -336,7 +351,7 @@ impl<'a> FacetDistribution<'a> { | ||||
|                     } | ||||
|                     .into()); | ||||
|                 } else { | ||||
|                     facets.clone() | ||||
|                     facets.into_iter().map(|(name, _)| name).cloned().collect() | ||||
|                 } | ||||
|             } | ||||
|             None => filterable_fields, | ||||
| @@ -345,7 +360,13 @@ impl<'a> FacetDistribution<'a> { | ||||
|         let mut distribution = BTreeMap::new(); | ||||
|         for (fid, name) in fields_ids_map.iter() { | ||||
|             if crate::is_faceted(name, &fields) { | ||||
|                 let values = self.facet_values(fid)?; | ||||
|                 let order_by = self | ||||
|                     .facets | ||||
|                     .as_ref() | ||||
|                     .map(|facets| facets.get(name).copied()) | ||||
|                     .flatten() | ||||
|                     .unwrap_or(self.default_order_by); | ||||
|                 let values = self.facet_values(fid, order_by)?; | ||||
|                 distribution.insert(name.to_string(), values); | ||||
|             } | ||||
|         } | ||||
| @@ -360,7 +381,7 @@ impl fmt::Debug for FacetDistribution<'_> { | ||||
|             facets, | ||||
|             candidates, | ||||
|             max_values_per_facet, | ||||
|             order_by, | ||||
|             default_order_by, | ||||
|             rtxn: _, | ||||
|             index: _, | ||||
|         } = self; | ||||
| @@ -369,7 +390,7 @@ impl fmt::Debug for FacetDistribution<'_> { | ||||
|             .field("facets", facets) | ||||
|             .field("candidates", candidates) | ||||
|             .field("max_values_per_facet", max_values_per_facet) | ||||
|             .field("order_by", order_by) | ||||
|             .field("default_order_by", default_order_by) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
| @@ -381,7 +402,7 @@ mod tests { | ||||
|  | ||||
|     use crate::documents::documents_batch_reader_from_objects; | ||||
|     use crate::index::tests::TempIndex; | ||||
|     use crate::{milli_snap, FacetDistribution}; | ||||
|     use crate::{milli_snap, FacetDistribution, OrderBy}; | ||||
|  | ||||
|     #[test] | ||||
|     fn few_candidates_few_facet_values() { | ||||
| @@ -406,14 +427,14 @@ mod tests { | ||||
|         let txn = index.read_txn().unwrap(); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
|  | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"Blue": 2, "RED": 1}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates([0, 1, 2].iter().copied().collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -421,7 +442,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"Blue": 2, "RED": 1}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates([1, 2].iter().copied().collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -432,7 +453,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"  blue": 1, "RED": 1}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates([2].iter().copied().collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -440,7 +461,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"RED": 1}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates([0, 1, 2].iter().copied().collect()) | ||||
|             .max_values_per_facet(1) | ||||
|             .execute() | ||||
| @@ -478,14 +499,14 @@ mod tests { | ||||
|         let txn = index.read_txn().unwrap(); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
|  | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"Blue": 4000, "Red": 6000}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .max_values_per_facet(1) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -493,7 +514,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"Blue": 4000}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..10_000).collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -501,7 +522,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"Blue": 4000, "Red": 6000}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..5_000).collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -509,7 +530,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"Blue": 2000, "Red": 3000}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..5_000).collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -517,7 +538,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), @r###"{"colour": {"Blue": 2000, "Red": 3000}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..5_000).collect()) | ||||
|             .max_values_per_facet(1) | ||||
|             .execute() | ||||
| @@ -555,14 +576,14 @@ mod tests { | ||||
|         let txn = index.read_txn().unwrap(); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
|  | ||||
|         milli_snap!(format!("{map:?}"), "no_candidates", @"ac9229ed5964d893af96a7076e2f8af5"); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .max_values_per_facet(2) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -570,7 +591,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), "no_candidates_with_max_2", @r###"{"colour": {"0": 10, "1": 10}}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..10_000).collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -578,7 +599,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), "candidates_0_10_000", @"ac9229ed5964d893af96a7076e2f8af5"); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..5_000).collect()) | ||||
|             .execute() | ||||
|             .unwrap(); | ||||
| @@ -615,14 +636,14 @@ mod tests { | ||||
|         let txn = index.read_txn().unwrap(); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
|  | ||||
|         milli_snap!(format!("{map:?}"), "no_candidates", @"{}"); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..1000).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
| @@ -630,7 +651,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), "candidates_0_1000", @r###"{"colour": (0.0, 999.0)}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((217..777).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
| @@ -667,14 +688,14 @@ mod tests { | ||||
|         let txn = index.read_txn().unwrap(); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
|  | ||||
|         milli_snap!(format!("{map:?}"), "no_candidates", @"{}"); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..1000).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
| @@ -682,7 +703,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), "candidates_0_1000", @r###"{"colour": (0.0, 1999.0)}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((217..777).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
| @@ -719,14 +740,14 @@ mod tests { | ||||
|         let txn = index.read_txn().unwrap(); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
|  | ||||
|         milli_snap!(format!("{map:?}"), "no_candidates", @"{}"); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..1000).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
| @@ -734,7 +755,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), "candidates_0_1000", @r###"{"colour": (0.0, 999.0)}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((217..777).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
| @@ -775,14 +796,14 @@ mod tests { | ||||
|         let txn = index.read_txn().unwrap(); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
|  | ||||
|         milli_snap!(format!("{map:?}"), "no_candidates", @"{}"); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((0..1000).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
| @@ -790,7 +811,7 @@ mod tests { | ||||
|         milli_snap!(format!("{map:?}"), "candidates_0_1000", @r###"{"colour": (0.0, 1998.0)}"###); | ||||
|  | ||||
|         let map = FacetDistribution::new(&txn, &index) | ||||
|             .facets(std::iter::once("colour")) | ||||
|             .facets(std::iter::once(("colour", OrderBy::default()))) | ||||
|             .candidates((217..777).collect()) | ||||
|             .compute_stats() | ||||
|             .unwrap(); | ||||
|   | ||||
| @@ -14,7 +14,7 @@ use crate::error::UserError; | ||||
| use crate::index::{DEFAULT_MIN_WORD_LEN_ONE_TYPO, DEFAULT_MIN_WORD_LEN_TWO_TYPOS}; | ||||
| use crate::update::index_documents::IndexDocumentsMethod; | ||||
| use crate::update::{IndexDocuments, UpdateIndexingStep}; | ||||
| use crate::{FieldsIdsMap, Index, Result}; | ||||
| use crate::{FieldsIdsMap, Index, OrderBy, Result}; | ||||
|  | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Copy)] | ||||
| pub enum Setting<T> { | ||||
| @@ -122,6 +122,7 @@ pub struct Settings<'a, 't, 'u, 'i> { | ||||
|     /// Attributes on which typo tolerance is disabled. | ||||
|     exact_attributes: Setting<HashSet<String>>, | ||||
|     max_values_per_facet: Setting<usize>, | ||||
|     sort_facet_values_by: Setting<HashMap<String, OrderBy>>, | ||||
|     pagination_max_total_hits: Setting<usize>, | ||||
| } | ||||
|  | ||||
| @@ -149,6 +150,7 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> { | ||||
|             min_word_len_one_typo: Setting::NotSet, | ||||
|             exact_attributes: Setting::NotSet, | ||||
|             max_values_per_facet: Setting::NotSet, | ||||
|             sort_facet_values_by: Setting::NotSet, | ||||
|             pagination_max_total_hits: Setting::NotSet, | ||||
|             indexer_config, | ||||
|         } | ||||
| @@ -275,6 +277,14 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> { | ||||
|         self.max_values_per_facet = Setting::Reset; | ||||
|     } | ||||
|  | ||||
|     pub fn set_sort_facet_values_by(&mut self, value: HashMap<String, OrderBy>) { | ||||
|         self.sort_facet_values_by = Setting::Set(value); | ||||
|     } | ||||
|  | ||||
|     pub fn reset_sort_facet_values_by(&mut self) { | ||||
|         self.sort_facet_values_by = Setting::Reset; | ||||
|     } | ||||
|  | ||||
|     pub fn set_pagination_max_total_hits(&mut self, value: usize) { | ||||
|         self.pagination_max_total_hits = Setting::Set(value); | ||||
|     } | ||||
| @@ -680,6 +690,20 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn update_sort_facet_values_by(&mut self) -> Result<()> { | ||||
|         match self.sort_facet_values_by.as_ref() { | ||||
|             Setting::Set(value) => { | ||||
|                 self.index.put_sort_facet_values_by(self.wtxn, value)?; | ||||
|             } | ||||
|             Setting::Reset => { | ||||
|                 self.index.delete_sort_facet_values_by(self.wtxn)?; | ||||
|             } | ||||
|             Setting::NotSet => (), | ||||
|         } | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn update_pagination_max_total_hits(&mut self) -> Result<()> { | ||||
|         match self.pagination_max_total_hits { | ||||
|             Setting::Set(max) => { | ||||
| @@ -714,6 +738,7 @@ impl<'a, 't, 'u, 'i> Settings<'a, 't, 'u, 'i> { | ||||
|         self.update_min_typo_word_len()?; | ||||
|         self.update_exact_words()?; | ||||
|         self.update_max_values_per_facet()?; | ||||
|         self.update_sort_facet_values_by()?; | ||||
|         self.update_pagination_max_total_hits()?; | ||||
|  | ||||
|         // If there is new faceted fields we indicate that we must reindex as we must | ||||
| @@ -1515,6 +1540,7 @@ mod tests { | ||||
|                     exact_words, | ||||
|                     exact_attributes, | ||||
|                     max_values_per_facet, | ||||
|                     sort_facet_values_by, | ||||
|                     pagination_max_total_hits, | ||||
|                 } = settings; | ||||
|                 assert!(matches!(searchable_fields, Setting::NotSet)); | ||||
| @@ -1532,6 +1558,7 @@ mod tests { | ||||
|                 assert!(matches!(exact_words, Setting::NotSet)); | ||||
|                 assert!(matches!(exact_attributes, Setting::NotSet)); | ||||
|                 assert!(matches!(max_values_per_facet, Setting::NotSet)); | ||||
|                 assert!(matches!(sort_facet_values_by, Setting::NotSet)); | ||||
|                 assert!(matches!(pagination_max_total_hits, Setting::NotSet)); | ||||
|             }) | ||||
|             .unwrap(); | ||||
|   | ||||
| @@ -5,7 +5,7 @@ use heed::EnvOpenOptions; | ||||
| use maplit::hashset; | ||||
| use milli::documents::{DocumentsBatchBuilder, DocumentsBatchReader}; | ||||
| use milli::update::{IndexDocuments, IndexDocumentsConfig, IndexerConfig, Settings}; | ||||
| use milli::{FacetDistribution, Index, Object}; | ||||
| use milli::{FacetDistribution, Index, Object, OrderBy}; | ||||
| use serde_json::Deserializer; | ||||
|  | ||||
| #[test] | ||||
| @@ -63,12 +63,12 @@ fn test_facet_distribution_with_no_facet_values() { | ||||
|  | ||||
|     let txn = index.read_txn().unwrap(); | ||||
|     let mut distrib = FacetDistribution::new(&txn, &index); | ||||
|     distrib.facets(vec!["genres"]); | ||||
|     distrib.facets(vec![("genres", OrderBy::default())]); | ||||
|     let result = distrib.execute().unwrap(); | ||||
|     assert_eq!(result["genres"].len(), 0); | ||||
|  | ||||
|     let mut distrib = FacetDistribution::new(&txn, &index); | ||||
|     distrib.facets(vec!["tags"]); | ||||
|     distrib.facets(vec![("tags", OrderBy::default())]); | ||||
|     let result = distrib.execute().unwrap(); | ||||
|     assert_eq!(result["tags"].len(), 2); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user