mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-26 20:15:07 +08:00
Expose a sortFacetValuesBy parameter to the user
This commit is contained in:
parent
80bbd4b6f3
commit
34b2e98fe9
@ -16,9 +16,9 @@ use crate::extractors::authentication::policies::*;
|
|||||||
use crate::extractors::authentication::GuardedData;
|
use crate::extractors::authentication::GuardedData;
|
||||||
use crate::extractors::sequential_extractor::SeqHandler;
|
use crate::extractors::sequential_extractor::SeqHandler;
|
||||||
use crate::search::{
|
use crate::search::{
|
||||||
add_search_rules, perform_search, MatchingStrategy, SearchQuery, DEFAULT_CROP_LENGTH,
|
add_search_rules, perform_search, FacetValuesSort, MatchingStrategy, SearchQuery,
|
||||||
DEFAULT_CROP_MARKER, DEFAULT_HIGHLIGHT_POST_TAG, DEFAULT_HIGHLIGHT_PRE_TAG,
|
DEFAULT_CROP_LENGTH, DEFAULT_CROP_MARKER, DEFAULT_HIGHLIGHT_POST_TAG,
|
||||||
DEFAULT_SEARCH_LIMIT, DEFAULT_SEARCH_OFFSET,
|
DEFAULT_HIGHLIGHT_PRE_TAG, DEFAULT_SEARCH_LIMIT, DEFAULT_SEARCH_OFFSET,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||||
@ -64,6 +64,8 @@ pub struct SearchQueryGet {
|
|||||||
show_ranking_score_details: Param<bool>,
|
show_ranking_score_details: Param<bool>,
|
||||||
#[deserr(default, error = DeserrQueryParamError<InvalidSearchFacets>)]
|
#[deserr(default, error = DeserrQueryParamError<InvalidSearchFacets>)]
|
||||||
facets: Option<CS<String>>,
|
facets: Option<CS<String>>,
|
||||||
|
#[deserr(default, error = DeserrQueryParamError<InvalidSearchFacets>)]
|
||||||
|
sort_facet_values_by: Option<FacetValuesSort>,
|
||||||
#[deserr( default = DEFAULT_HIGHLIGHT_PRE_TAG(), error = DeserrQueryParamError<InvalidSearchHighlightPreTag>)]
|
#[deserr( default = DEFAULT_HIGHLIGHT_PRE_TAG(), error = DeserrQueryParamError<InvalidSearchHighlightPreTag>)]
|
||||||
highlight_pre_tag: String,
|
highlight_pre_tag: String,
|
||||||
#[deserr( default = DEFAULT_HIGHLIGHT_POST_TAG(), error = DeserrQueryParamError<InvalidSearchHighlightPostTag>)]
|
#[deserr( default = DEFAULT_HIGHLIGHT_POST_TAG(), error = DeserrQueryParamError<InvalidSearchHighlightPostTag>)]
|
||||||
@ -103,6 +105,7 @@ impl From<SearchQueryGet> for SearchQuery {
|
|||||||
show_ranking_score: other.show_ranking_score.0,
|
show_ranking_score: other.show_ranking_score.0,
|
||||||
show_ranking_score_details: other.show_ranking_score_details.0,
|
show_ranking_score_details: other.show_ranking_score_details.0,
|
||||||
facets: other.facets.map(|o| o.into_iter().collect()),
|
facets: other.facets.map(|o| o.into_iter().collect()),
|
||||||
|
sort_facet_values_by: other.sort_facet_values_by,
|
||||||
highlight_pre_tag: other.highlight_pre_tag,
|
highlight_pre_tag: other.highlight_pre_tag,
|
||||||
highlight_post_tag: other.highlight_post_tag,
|
highlight_post_tag: other.highlight_post_tag,
|
||||||
crop_marker: other.crop_marker,
|
crop_marker: other.crop_marker,
|
||||||
|
@ -14,7 +14,7 @@ use meilisearch_types::heed::RoTxn;
|
|||||||
use meilisearch_types::index_uid::IndexUid;
|
use meilisearch_types::index_uid::IndexUid;
|
||||||
use meilisearch_types::milli::score_details::{ScoreDetails, ScoringStrategy};
|
use meilisearch_types::milli::score_details::{ScoreDetails, ScoringStrategy};
|
||||||
use meilisearch_types::milli::{
|
use meilisearch_types::milli::{
|
||||||
dot_product_similarity, FacetValueHit, InternalError, SearchForFacetValues,
|
dot_product_similarity, FacetValueHit, OrderBy, InternalError, SearchForFacetValues,
|
||||||
};
|
};
|
||||||
use meilisearch_types::settings::DEFAULT_PAGINATION_MAX_TOTAL_HITS;
|
use meilisearch_types::settings::DEFAULT_PAGINATION_MAX_TOTAL_HITS;
|
||||||
use meilisearch_types::{milli, Document};
|
use meilisearch_types::{milli, Document};
|
||||||
@ -74,6 +74,8 @@ pub struct SearchQuery {
|
|||||||
pub sort: Option<Vec<String>>,
|
pub sort: Option<Vec<String>>,
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSearchFacets>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSearchFacets>)]
|
||||||
pub facets: Option<Vec<String>>,
|
pub facets: Option<Vec<String>>,
|
||||||
|
#[deserr(default, error = DeserrJsonError<InvalidSearchFacets>)] // TODO
|
||||||
|
pub sort_facet_values_by: Option<FacetValuesSort>,
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPreTag>, default = DEFAULT_HIGHLIGHT_PRE_TAG())]
|
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPreTag>, default = DEFAULT_HIGHLIGHT_PRE_TAG())]
|
||||||
pub highlight_pre_tag: String,
|
pub highlight_pre_tag: String,
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPostTag>, default = DEFAULT_HIGHLIGHT_POST_TAG())]
|
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPostTag>, default = DEFAULT_HIGHLIGHT_POST_TAG())]
|
||||||
@ -133,6 +135,8 @@ pub struct SearchQueryWithIndex {
|
|||||||
pub sort: Option<Vec<String>>,
|
pub sort: Option<Vec<String>>,
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSearchFacets>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSearchFacets>)]
|
||||||
pub facets: Option<Vec<String>>,
|
pub facets: Option<Vec<String>>,
|
||||||
|
#[deserr(default, error = DeserrJsonError<InvalidSearchFacets>)] // TODO
|
||||||
|
pub sort_facet_values_by: Option<FacetValuesSort>,
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPreTag>, default = DEFAULT_HIGHLIGHT_PRE_TAG())]
|
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPreTag>, default = DEFAULT_HIGHLIGHT_PRE_TAG())]
|
||||||
pub highlight_pre_tag: String,
|
pub highlight_pre_tag: String,
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPostTag>, default = DEFAULT_HIGHLIGHT_POST_TAG())]
|
#[deserr(default, error = DeserrJsonError<InvalidSearchHighlightPostTag>, default = DEFAULT_HIGHLIGHT_POST_TAG())]
|
||||||
@ -165,6 +169,7 @@ impl SearchQueryWithIndex {
|
|||||||
filter,
|
filter,
|
||||||
sort,
|
sort,
|
||||||
facets,
|
facets,
|
||||||
|
sort_facet_values_by,
|
||||||
highlight_pre_tag,
|
highlight_pre_tag,
|
||||||
highlight_post_tag,
|
highlight_post_tag,
|
||||||
crop_marker,
|
crop_marker,
|
||||||
@ -190,6 +195,7 @@ impl SearchQueryWithIndex {
|
|||||||
filter,
|
filter,
|
||||||
sort,
|
sort,
|
||||||
facets,
|
facets,
|
||||||
|
sort_facet_values_by,
|
||||||
highlight_pre_tag,
|
highlight_pre_tag,
|
||||||
highlight_post_tag,
|
highlight_post_tag,
|
||||||
crop_marker,
|
crop_marker,
|
||||||
@ -226,6 +232,26 @@ impl From<MatchingStrategy> for TermsMatchingStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserr)]
|
||||||
|
#[deserr(rename_all = camelCase)]
|
||||||
|
pub enum FacetValuesSort {
|
||||||
|
/// Facet values are sorted by decreasing count.
|
||||||
|
/// The count is the number of records containing this facet value in the results of the query.
|
||||||
|
#[default]
|
||||||
|
Alpha,
|
||||||
|
/// Facet values are sorted in alphabetical order, ascending from A to Z.
|
||||||
|
Count,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<OrderBy> for FacetValuesSort {
|
||||||
|
fn into(self) -> OrderBy {
|
||||||
|
match self {
|
||||||
|
FacetValuesSort::Alpha => OrderBy::Lexicographic,
|
||||||
|
FacetValuesSort::Count => OrderBy::Count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||||
pub struct SearchHit {
|
pub struct SearchHit {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@ -557,7 +583,10 @@ pub fn perform_search(
|
|||||||
if fields.iter().all(|f| f != "*") {
|
if fields.iter().all(|f| f != "*") {
|
||||||
facet_distribution.facets(fields);
|
facet_distribution.facets(fields);
|
||||||
}
|
}
|
||||||
let distribution = facet_distribution.candidates(candidates).execute()?;
|
let distribution = facet_distribution
|
||||||
|
.candidates(candidates)
|
||||||
|
.order_by(query.sort_facet_values_by.map_or_else(Default::default, Into::into))
|
||||||
|
.execute()?;
|
||||||
let stats = facet_distribution.compute_stats()?;
|
let stats = facet_distribution.compute_stats()?;
|
||||||
(Some(distribution), Some(stats))
|
(Some(distribution), Some(stats))
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ pub use self::heed_codec::{
|
|||||||
pub use self::index::Index;
|
pub use self::index::Index;
|
||||||
pub use self::search::{
|
pub use self::search::{
|
||||||
FacetDistribution, FacetValueHit, Filter, FormatOptions, MatchBounds, MatcherBuilder,
|
FacetDistribution, FacetValueHit, Filter, FormatOptions, MatchBounds, MatcherBuilder,
|
||||||
MatchingWords, Search, SearchForFacetValues, SearchResult, TermsMatchingStrategy,
|
MatchingWords, OrderBy, Search, SearchForFacetValues, SearchResult, TermsMatchingStrategy,
|
||||||
DEFAULT_VALUES_PER_FACET,
|
DEFAULT_VALUES_PER_FACET,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,11 +12,10 @@ use crate::heed_codec::facet::{
|
|||||||
FacetGroupKeyCodec, FieldDocIdFacetF64Codec, FieldDocIdFacetStringCodec, OrderedF64Codec,
|
FacetGroupKeyCodec, FieldDocIdFacetF64Codec, FieldDocIdFacetStringCodec, OrderedF64Codec,
|
||||||
};
|
};
|
||||||
use crate::heed_codec::{ByteSliceRefCodec, StrRefCodec};
|
use crate::heed_codec::{ByteSliceRefCodec, StrRefCodec};
|
||||||
use crate::search::facet::facet_distribution_iter;
|
use crate::search::facet::facet_distribution_iter::{
|
||||||
use crate::{FieldId, Index, Result};
|
|
||||||
use facet_distribution_iter::{
|
|
||||||
count_iterate_over_facet_distribution, lexicographically_iterate_over_facet_distribution,
|
count_iterate_over_facet_distribution, lexicographically_iterate_over_facet_distribution,
|
||||||
};
|
};
|
||||||
|
use crate::{FieldId, Index, Result};
|
||||||
|
|
||||||
/// The default number of values by facets that will
|
/// The default number of values by facets that will
|
||||||
/// be fetched from the key-value store.
|
/// be fetched from the key-value store.
|
||||||
@ -27,9 +26,10 @@ pub const DEFAULT_VALUES_PER_FACET: usize = 100;
|
|||||||
const CANDIDATES_THRESHOLD: u64 = 3000;
|
const CANDIDATES_THRESHOLD: u64 = 3000;
|
||||||
|
|
||||||
/// How should we fetch the facets?
|
/// How should we fetch the facets?
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum OrderBy {
|
pub enum OrderBy {
|
||||||
/// By lexicographic order...
|
/// By lexicographic order...
|
||||||
|
#[default]
|
||||||
Lexicographic,
|
Lexicographic,
|
||||||
/// Or by number of docids in common?
|
/// Or by number of docids in common?
|
||||||
Count,
|
Count,
|
||||||
@ -50,7 +50,7 @@ impl<'a> FacetDistribution<'a> {
|
|||||||
facets: None,
|
facets: None,
|
||||||
candidates: None,
|
candidates: None,
|
||||||
max_values_per_facet: DEFAULT_VALUES_PER_FACET,
|
max_values_per_facet: DEFAULT_VALUES_PER_FACET,
|
||||||
order_by: OrderBy::Count,
|
order_by: OrderBy::default(),
|
||||||
rtxn,
|
rtxn,
|
||||||
index,
|
index,
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use heed::types::{ByteSlice, DecodeIgnore};
|
|||||||
use heed::{BytesDecode, RoTxn};
|
use heed::{BytesDecode, RoTxn};
|
||||||
use roaring::RoaringBitmap;
|
use roaring::RoaringBitmap;
|
||||||
|
|
||||||
pub use self::facet_distribution::{FacetDistribution, DEFAULT_VALUES_PER_FACET};
|
pub use self::facet_distribution::{FacetDistribution, OrderBy, DEFAULT_VALUES_PER_FACET};
|
||||||
pub use self::filter::{BadGeoError, Filter};
|
pub use self::filter::{BadGeoError, Filter};
|
||||||
use crate::heed_codec::facet::{FacetGroupKeyCodec, FacetGroupValueCodec, OrderedF64Codec};
|
use crate::heed_codec::facet::{FacetGroupKeyCodec, FacetGroupValueCodec, OrderedF64Codec};
|
||||||
use crate::heed_codec::ByteSliceRefCodec;
|
use crate::heed_codec::ByteSliceRefCodec;
|
||||||
|
@ -7,7 +7,7 @@ use log::error;
|
|||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use roaring::bitmap::RoaringBitmap;
|
use roaring::bitmap::RoaringBitmap;
|
||||||
|
|
||||||
pub use self::facet::{FacetDistribution, Filter, DEFAULT_VALUES_PER_FACET};
|
pub use self::facet::{FacetDistribution, Filter, OrderBy, DEFAULT_VALUES_PER_FACET};
|
||||||
pub use self::new::matches::{FormatOptions, MatchBounds, Matcher, MatcherBuilder, MatchingWords};
|
pub use self::new::matches::{FormatOptions, MatchBounds, Matcher, MatcherBuilder, MatchingWords};
|
||||||
use self::new::PartialSearchResult;
|
use self::new::PartialSearchResult;
|
||||||
use crate::error::UserError;
|
use crate::error::UserError;
|
||||||
|
Loading…
Reference in New Issue
Block a user