mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-01-31 15:31:53 +08:00
Finish document addition pipeline
This commit is contained in:
parent
2d7971bd40
commit
deea0c44ea
@ -12,7 +12,7 @@ use milli::index::{IndexEmbeddingConfig, PrefixSearch};
|
|||||||
use milli::proximity::ProximityPrecision;
|
use milli::proximity::ProximityPrecision;
|
||||||
use milli::update::Setting;
|
use milli::update::Setting;
|
||||||
use milli::{
|
use milli::{
|
||||||
Criterion, CriterionError, FilterableAttributesSettings, Index, DEFAULT_VALUES_PER_FACET,
|
Criterion, CriterionError, FilterableAttributesRule, Index, DEFAULT_VALUES_PER_FACET,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
@ -204,8 +204,8 @@ pub struct Settings<T> {
|
|||||||
/// Attributes to use for faceting and filtering. See [Filtering and Faceted Search](https://www.meilisearch.com/docs/learn/filtering_and_sorting/search_with_facet_filters).
|
/// Attributes to use for faceting and filtering. See [Filtering and Faceted Search](https://www.meilisearch.com/docs/learn/filtering_and_sorting/search_with_facet_filters).
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsFilterableAttributes>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsFilterableAttributes>)]
|
||||||
#[schema(value_type = Option<Vec<FilterableAttributesSettings>>, example = json!(["release_date", "genre"]))]
|
#[schema(value_type = Option<Vec<FilterableAttributesRule>>, example = json!(["release_date", "genre"]))]
|
||||||
pub filterable_attributes: Setting<Vec<FilterableAttributesSettings>>,
|
pub filterable_attributes: Setting<Vec<FilterableAttributesRule>>,
|
||||||
/// Attributes to use when sorting search results.
|
/// Attributes to use when sorting search results.
|
||||||
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
#[serde(default, skip_serializing_if = "Setting::is_not_set")]
|
||||||
#[deserr(default, error = DeserrJsonError<InvalidSettingsSortableAttributes>)]
|
#[deserr(default, error = DeserrJsonError<InvalidSettingsSortableAttributes>)]
|
||||||
@ -793,7 +793,7 @@ pub fn settings(
|
|||||||
.user_defined_searchable_fields(rtxn)?
|
.user_defined_searchable_fields(rtxn)?
|
||||||
.map(|fields| fields.into_iter().map(String::from).collect());
|
.map(|fields| fields.into_iter().map(String::from).collect());
|
||||||
|
|
||||||
let filterable_attributes = index.filterable_fields(rtxn)?.into_iter().collect();
|
let filterable_attributes = index.filterable_attributes_rules(rtxn)?.into_iter().collect();
|
||||||
|
|
||||||
let sortable_attributes = index.sortable_fields(rtxn)?.into_iter().collect();
|
let sortable_attributes = index.sortable_fields(rtxn)?.into_iter().collect();
|
||||||
|
|
||||||
|
@ -105,6 +105,11 @@ impl<'indexing> GlobalFieldsIdsMap<'indexing> {
|
|||||||
|
|
||||||
self.local.name(id)
|
self.local.name(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the metadata of a field based on its id.
|
||||||
|
pub fn metadata(&self, id: FieldId) -> Option<Metadata> {
|
||||||
|
self.local.metadata(id).or_else(|| self.global.read().unwrap().metadata(id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'indexing> MutFieldIdMapper for GlobalFieldsIdsMap<'indexing> {
|
impl<'indexing> MutFieldIdMapper for GlobalFieldsIdsMap<'indexing> {
|
||||||
|
@ -7,7 +7,7 @@ use heed::RoTxn;
|
|||||||
use super::FieldsIdsMap;
|
use super::FieldsIdsMap;
|
||||||
use crate::attribute_patterns::PatternMatch;
|
use crate::attribute_patterns::PatternMatch;
|
||||||
use crate::{
|
use crate::{
|
||||||
FieldId, FilterableAttributesFeatures, FilterableAttributesSettings, Index,
|
is_faceted_by, FieldId, FilterableAttributesFeatures, FilterableAttributesRule, Index,
|
||||||
LocalizedAttributesRule, Result,
|
LocalizedAttributesRule, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -113,8 +113,8 @@ impl Metadata {
|
|||||||
|
|
||||||
pub fn filterable_attributes<'rules>(
|
pub fn filterable_attributes<'rules>(
|
||||||
&self,
|
&self,
|
||||||
rules: &'rules [FilterableAttributesSettings],
|
rules: &'rules [FilterableAttributesRule],
|
||||||
) -> Option<&'rules FilterableAttributesSettings> {
|
) -> Option<&'rules FilterableAttributesRule> {
|
||||||
let filterable_attributes_rule_id = self.filterable_attributes_rule_id?.get();
|
let filterable_attributes_rule_id = self.filterable_attributes_rule_id?.get();
|
||||||
// - 1: `filterable_attributes_rule_id` is NonZero
|
// - 1: `filterable_attributes_rule_id` is NonZero
|
||||||
let rule = rules.get((filterable_attributes_rule_id - 1) as usize).unwrap();
|
let rule = rules.get((filterable_attributes_rule_id - 1) as usize).unwrap();
|
||||||
@ -123,7 +123,7 @@ impl Metadata {
|
|||||||
|
|
||||||
pub fn filterable_attributes_features(
|
pub fn filterable_attributes_features(
|
||||||
&self,
|
&self,
|
||||||
rules: &[FilterableAttributesSettings],
|
rules: &[FilterableAttributesRule],
|
||||||
) -> FilterableAttributesFeatures {
|
) -> FilterableAttributesFeatures {
|
||||||
self.filterable_attributes(rules)
|
self.filterable_attributes(rules)
|
||||||
.map(|rule| rule.features())
|
.map(|rule| rule.features())
|
||||||
@ -138,21 +138,42 @@ impl Metadata {
|
|||||||
pub fn is_searchable(&self) -> bool {
|
pub fn is_searchable(&self) -> bool {
|
||||||
self.searchable
|
self.searchable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the field is part of the facet databases. (sortable, filterable, or facet searchable)
|
||||||
|
pub fn is_faceted(&self, rules: &[FilterableAttributesRule]) -> bool {
|
||||||
|
if self.is_sortable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let features = self.filterable_attributes_features(&rules);
|
||||||
|
if features.is_filterable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if features.is_facet_searchable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MetadataBuilder {
|
pub struct MetadataBuilder {
|
||||||
searchable_attributes: Vec<String>,
|
searchable_attributes: Option<Vec<String>>,
|
||||||
filterable_attributes: Vec<FilterableAttributesSettings>,
|
filterable_attributes: Vec<FilterableAttributesRule>,
|
||||||
sortable_attributes: HashSet<String>,
|
sortable_attributes: HashSet<String>,
|
||||||
localized_attributes: Option<Vec<LocalizedAttributesRule>>,
|
localized_attributes: Option<Vec<LocalizedAttributesRule>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetadataBuilder {
|
impl MetadataBuilder {
|
||||||
pub fn from_index(index: &Index, rtxn: &RoTxn) -> Result<Self> {
|
pub fn from_index(index: &Index, rtxn: &RoTxn) -> Result<Self> {
|
||||||
let searchable_attributes =
|
let searchable_attributes = match index.user_defined_searchable_fields(rtxn)? {
|
||||||
index.searchable_fields(rtxn)?.into_iter().map(|s| s.to_string()).collect();
|
Some(fields) if fields.contains(&"*") => None,
|
||||||
let filterable_attributes = index.filterable_fields(rtxn)?;
|
None => None,
|
||||||
|
Some(fields) => Some(fields.into_iter().map(|s| s.to_string()).collect()),
|
||||||
|
};
|
||||||
|
let filterable_attributes = index.filterable_attributes_rules(rtxn)?;
|
||||||
let sortable_attributes = index.sortable_fields(rtxn)?;
|
let sortable_attributes = index.sortable_fields(rtxn)?;
|
||||||
let localized_attributes = index.localized_attributes_rules(rtxn)?;
|
let localized_attributes = index.localized_attributes_rules(rtxn)?;
|
||||||
|
|
||||||
@ -164,27 +185,35 @@ impl MetadataBuilder {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
// pub fn new(
|
||||||
searchable_attributes: Vec<String>,
|
// searchable_attributes: Option<Vec<String>>,
|
||||||
filterable_attributes: Vec<FilterableAttributesSettings>,
|
// filterable_attributes: Vec<FilterableAttributesRule>,
|
||||||
sortable_attributes: HashSet<String>,
|
// sortable_attributes: HashSet<String>,
|
||||||
localized_attributes: Option<Vec<LocalizedAttributesRule>>,
|
// localized_attributes: Option<Vec<LocalizedAttributesRule>>,
|
||||||
) -> Self {
|
// ) -> Self {
|
||||||
Self {
|
// let searchable_attributes = match searchable_attributes {
|
||||||
searchable_attributes,
|
// Some(fields) if fields.iter().any(|f| f == "*") => None,
|
||||||
filterable_attributes,
|
// None => None,
|
||||||
sortable_attributes,
|
// Some(fields) => Some(fields),
|
||||||
localized_attributes,
|
// };
|
||||||
}
|
|
||||||
}
|
// Self {
|
||||||
|
// searchable_attributes,
|
||||||
|
// filterable_attributes,
|
||||||
|
// sortable_attributes,
|
||||||
|
// localized_attributes,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn metadata_for_field(&self, field: &str) -> Metadata {
|
pub fn metadata_for_field(&self, field: &str) -> Metadata {
|
||||||
let searchable = self
|
let searchable = match &self.searchable_attributes {
|
||||||
.searchable_attributes
|
// A field is searchable if it is faceted by a searchable attribute
|
||||||
.iter()
|
Some(attributes) => attributes.iter().any(|pattern| is_faceted_by(field, pattern)),
|
||||||
.any(|attribute| attribute == "*" || attribute == field);
|
None => true,
|
||||||
|
};
|
||||||
|
|
||||||
let sortable = self.sortable_attributes.contains(field);
|
// A field is sortable if it is faceted by a sortable attribute
|
||||||
|
let sortable = self.sortable_attributes.iter().any(|pattern| is_faceted_by(field, pattern));
|
||||||
|
|
||||||
let localized_attributes_rule_id = self
|
let localized_attributes_rule_id = self
|
||||||
.localized_attributes
|
.localized_attributes
|
||||||
@ -209,15 +238,15 @@ impl MetadataBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn searchable_attributes(&self) -> &[String] {
|
pub fn searchable_attributes(&self) -> Option<&[String]> {
|
||||||
self.searchable_attributes.as_slice()
|
self.searchable_attributes.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sortable_attributes(&self) -> &HashSet<String> {
|
pub fn sortable_attributes(&self) -> &HashSet<String> {
|
||||||
&self.sortable_attributes
|
&self.sortable_attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filterable_attributes(&self) -> &[FilterableAttributesSettings] {
|
pub fn filterable_attributes(&self) -> &[FilterableAttributesRule] {
|
||||||
&self.filterable_attributes
|
&self.filterable_attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,29 +11,27 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, ToSchema)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, ToSchema)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum FilterableAttributesSettings {
|
pub enum FilterableAttributesRule {
|
||||||
Field(String),
|
Field(String),
|
||||||
Pattern(FilterableAttributesPatterns),
|
Pattern(FilterableAttributesPatterns),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterableAttributesSettings {
|
impl FilterableAttributesRule {
|
||||||
pub fn match_str(&self, field: &str) -> PatternMatch {
|
pub fn match_str(&self, field: &str) -> PatternMatch {
|
||||||
match self {
|
match self {
|
||||||
FilterableAttributesSettings::Field(pattern) => match_field_legacy(pattern, field),
|
FilterableAttributesRule::Field(pattern) => match_field_legacy(pattern, field),
|
||||||
FilterableAttributesSettings::Pattern(patterns) => patterns.match_str(field),
|
FilterableAttributesRule::Pattern(patterns) => patterns.match_str(field),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_geo(&self) -> bool {
|
pub fn has_geo(&self) -> bool {
|
||||||
matches!(self, FilterableAttributesSettings::Field(field_name) if field_name == RESERVED_GEO_FIELD_NAME)
|
matches!(self, FilterableAttributesRule::Field(field_name) if field_name == RESERVED_GEO_FIELD_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn features(&self) -> FilterableAttributesFeatures {
|
pub fn features(&self) -> FilterableAttributesFeatures {
|
||||||
match self {
|
match self {
|
||||||
FilterableAttributesSettings::Field(_) => {
|
FilterableAttributesRule::Field(_) => FilterableAttributesFeatures::legacy_default(),
|
||||||
FilterableAttributesFeatures::legacy_default()
|
FilterableAttributesRule::Pattern(patterns) => patterns.features(),
|
||||||
}
|
|
||||||
FilterableAttributesSettings::Pattern(patterns) => patterns.features(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,6 +91,11 @@ impl FilterableAttributesFeatures {
|
|||||||
self.filter != FilterFeature::Disabled
|
self.filter != FilterFeature::Disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if `IS EXISTS` is allowed
|
||||||
|
pub fn is_filterable_exists(&self) -> bool {
|
||||||
|
self.filter != FilterFeature::Disabled
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if `<`, `>`, `<=`, `>=` or `TO` are allowed
|
/// Check if `<`, `>`, `<=`, `>=` or `TO` are allowed
|
||||||
pub fn is_filterable_order(&self) -> bool {
|
pub fn is_filterable_order(&self) -> bool {
|
||||||
self.filter == FilterFeature::Order
|
self.filter == FilterFeature::Order
|
||||||
@ -104,7 +107,7 @@ impl FilterableAttributesFeatures {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: DeserializeError> Deserr<E> for FilterableAttributesSettings {
|
impl<E: DeserializeError> Deserr<E> for FilterableAttributesRule {
|
||||||
fn deserialize_from_value<V: deserr::IntoValue>(
|
fn deserialize_from_value<V: deserr::IntoValue>(
|
||||||
value: deserr::Value<V>,
|
value: deserr::Value<V>,
|
||||||
location: ValuePointerRef,
|
location: ValuePointerRef,
|
||||||
@ -127,7 +130,7 @@ pub enum FilterFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn matching_field_ids(
|
pub fn matching_field_ids(
|
||||||
filterable_attributes: &[FilterableAttributesSettings],
|
filterable_attributes: &[FilterableAttributesRule],
|
||||||
fields_ids_map: &FieldsIdsMap,
|
fields_ids_map: &FieldsIdsMap,
|
||||||
) -> HashSet<FieldId> {
|
) -> HashSet<FieldId> {
|
||||||
let mut result = HashSet::new();
|
let mut result = HashSet::new();
|
||||||
@ -142,14 +145,14 @@ pub fn matching_field_ids(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn matching_field_names<'fim>(
|
pub fn matching_field_names<'fim>(
|
||||||
filterable_attributes: &[FilterableAttributesSettings],
|
filterable_attributes: &[FilterableAttributesRule],
|
||||||
fields_ids_map: &'fim FieldsIdsMap,
|
fields_ids_map: &'fim FieldsIdsMap,
|
||||||
) -> BTreeSet<&'fim str> {
|
) -> BTreeSet<&'fim str> {
|
||||||
filtered_matching_field_names(filterable_attributes, fields_ids_map, &|_| true)
|
filtered_matching_field_names(filterable_attributes, fields_ids_map, &|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filtered_matching_field_names<'fim>(
|
pub fn filtered_matching_field_names<'fim>(
|
||||||
filterable_attributes: &[FilterableAttributesSettings],
|
filterable_attributes: &[FilterableAttributesRule],
|
||||||
fields_ids_map: &'fim FieldsIdsMap,
|
fields_ids_map: &'fim FieldsIdsMap,
|
||||||
filter: &impl Fn(&FilterableAttributesFeatures) -> bool,
|
filter: &impl Fn(&FilterableAttributesFeatures) -> bool,
|
||||||
) -> BTreeSet<&'fim str> {
|
) -> BTreeSet<&'fim str> {
|
||||||
@ -169,7 +172,7 @@ pub fn filtered_matching_field_names<'fim>(
|
|||||||
|
|
||||||
pub fn matching_features(
|
pub fn matching_features(
|
||||||
field_name: &str,
|
field_name: &str,
|
||||||
filterable_attributes: &[FilterableAttributesSettings],
|
filterable_attributes: &[FilterableAttributesRule],
|
||||||
) -> Option<FilterableAttributesFeatures> {
|
) -> Option<FilterableAttributesFeatures> {
|
||||||
for filterable_attribute in filterable_attributes {
|
for filterable_attribute in filterable_attributes {
|
||||||
if filterable_attribute.match_str(field_name) == PatternMatch::Match {
|
if filterable_attribute.match_str(field_name) == PatternMatch::Match {
|
||||||
@ -181,7 +184,7 @@ pub fn matching_features(
|
|||||||
|
|
||||||
pub fn is_field_filterable(
|
pub fn is_field_filterable(
|
||||||
field_name: &str,
|
field_name: &str,
|
||||||
filterable_attributes: &[FilterableAttributesSettings],
|
filterable_attributes: &[FilterableAttributesRule],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
matching_features(field_name, filterable_attributes)
|
matching_features(field_name, filterable_attributes)
|
||||||
.map_or(false, |features| features.is_filterable())
|
.map_or(false, |features| features.is_filterable())
|
||||||
@ -189,7 +192,7 @@ pub fn is_field_filterable(
|
|||||||
|
|
||||||
pub fn match_pattern_by_features(
|
pub fn match_pattern_by_features(
|
||||||
field_name: &str,
|
field_name: &str,
|
||||||
filterable_attributes: &[FilterableAttributesSettings],
|
filterable_attributes: &[FilterableAttributesRule],
|
||||||
filter: &impl Fn(&FilterableAttributesFeatures) -> bool,
|
filter: &impl Fn(&FilterableAttributesFeatures) -> bool,
|
||||||
) -> PatternMatch {
|
) -> PatternMatch {
|
||||||
let mut selection = PatternMatch::NoMatch;
|
let mut selection = PatternMatch::NoMatch;
|
@ -15,7 +15,7 @@ use crate::constants::{RESERVED_GEO_FIELD_NAME, RESERVED_VECTORS_FIELD_NAME};
|
|||||||
use crate::documents::PrimaryKey;
|
use crate::documents::PrimaryKey;
|
||||||
use crate::error::{InternalError, UserError};
|
use crate::error::{InternalError, UserError};
|
||||||
use crate::fields_ids_map::FieldsIdsMap;
|
use crate::fields_ids_map::FieldsIdsMap;
|
||||||
use crate::filterable_fields::{match_pattern_by_features, matching_field_ids};
|
use crate::filterable_attributes_rules::match_pattern_by_features;
|
||||||
use crate::heed_codec::facet::{
|
use crate::heed_codec::facet::{
|
||||||
FacetGroupKeyCodec, FacetGroupValueCodec, FieldDocIdFacetF64Codec, FieldDocIdFacetStringCodec,
|
FacetGroupKeyCodec, FacetGroupValueCodec, FieldDocIdFacetF64Codec, FieldDocIdFacetStringCodec,
|
||||||
FieldIdCodec, OrderedF64Codec,
|
FieldIdCodec, OrderedF64Codec,
|
||||||
@ -27,7 +27,7 @@ use crate::vector::{ArroyWrapper, Embedding, EmbeddingConfig};
|
|||||||
use crate::{
|
use crate::{
|
||||||
default_criteria, CboRoaringBitmapCodec, Criterion, DocumentId, ExternalDocumentsIds,
|
default_criteria, CboRoaringBitmapCodec, Criterion, DocumentId, ExternalDocumentsIds,
|
||||||
FacetDistribution, FieldDistribution, FieldId, FieldIdMapMissingEntry, FieldIdWordCountCodec,
|
FacetDistribution, FieldDistribution, FieldId, FieldIdMapMissingEntry, FieldIdWordCountCodec,
|
||||||
FieldidsWeightsMap, FilterableAttributesSettings, GeoPoint, LocalizedAttributesRule, ObkvCodec,
|
FieldidsWeightsMap, FilterableAttributesRule, GeoPoint, LocalizedAttributesRule, ObkvCodec,
|
||||||
Result, RoaringBitmapCodec, RoaringBitmapLenCodec, Search, U8StrStrCodec, Weight, BEU16, BEU32,
|
Result, RoaringBitmapCodec, RoaringBitmapLenCodec, Search, U8StrStrCodec, Weight, BEU16, BEU32,
|
||||||
BEU64,
|
BEU64,
|
||||||
};
|
};
|
||||||
@ -786,11 +786,11 @@ impl Index {
|
|||||||
|
|
||||||
/* filterable fields */
|
/* filterable fields */
|
||||||
|
|
||||||
/// Writes the filterable fields names in the database.
|
/// Writes the filterable attributes rules in the database.
|
||||||
pub(crate) fn put_filterable_fields(
|
pub(crate) fn put_filterable_attributes_rules(
|
||||||
&self,
|
&self,
|
||||||
wtxn: &mut RwTxn<'_>,
|
wtxn: &mut RwTxn<'_>,
|
||||||
fields: &Vec<FilterableAttributesSettings>,
|
fields: &Vec<FilterableAttributesRule>,
|
||||||
) -> heed::Result<()> {
|
) -> heed::Result<()> {
|
||||||
self.main.remap_types::<Str, SerdeJson<_>>().put(
|
self.main.remap_types::<Str, SerdeJson<_>>().put(
|
||||||
wtxn,
|
wtxn,
|
||||||
@ -799,16 +799,19 @@ impl Index {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes the filterable fields ids in the database.
|
/// Deletes the filterable attributes rules in the database.
|
||||||
pub(crate) fn delete_filterable_fields(&self, wtxn: &mut RwTxn<'_>) -> heed::Result<bool> {
|
pub(crate) fn delete_filterable_attributes_rules(
|
||||||
|
&self,
|
||||||
|
wtxn: &mut RwTxn<'_>,
|
||||||
|
) -> heed::Result<bool> {
|
||||||
self.main.remap_key_type::<Str>().delete(wtxn, main_key::FILTERABLE_FIELDS_KEY)
|
self.main.remap_key_type::<Str>().delete(wtxn, main_key::FILTERABLE_FIELDS_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the filterable fields setting value.
|
/// Returns the filterable attributes rules.
|
||||||
pub fn filterable_fields(
|
pub fn filterable_attributes_rules(
|
||||||
&self,
|
&self,
|
||||||
rtxn: &RoTxn<'_>,
|
rtxn: &RoTxn<'_>,
|
||||||
) -> heed::Result<Vec<FilterableAttributesSettings>> {
|
) -> heed::Result<Vec<FilterableAttributesRule>> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.main
|
.main
|
||||||
.remap_types::<Str, SerdeJson<_>>()
|
.remap_types::<Str, SerdeJson<_>>()
|
||||||
@ -817,14 +820,14 @@ impl Index {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the filterable fields ids.
|
/// Returns the filterable fields ids.
|
||||||
pub fn filterable_fields_ids(&self, rtxn: &RoTxn<'_>) -> Result<HashSet<FieldId>> {
|
// pub fn filterable_fields_ids(&self, rtxn: &RoTxn<'_>) -> Result<HashSet<FieldId>> {
|
||||||
let fields = self.filterable_fields(rtxn)?;
|
// let fields = self.filterable_attributes_rules(rtxn)?;
|
||||||
let fields_ids_map = self.fields_ids_map(rtxn)?;
|
// let fields_ids_map = self.fields_ids_map(rtxn)?;
|
||||||
|
|
||||||
let matching_field_ids = matching_field_ids(&fields, &fields_ids_map);
|
// let matching_field_ids = matching_field_ids(&fields, &fields_ids_map);
|
||||||
|
|
||||||
Ok(matching_field_ids)
|
// Ok(matching_field_ids)
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* sortable fields */
|
/* sortable fields */
|
||||||
|
|
||||||
@ -865,17 +868,17 @@ impl Index {
|
|||||||
/* faceted fields */
|
/* faceted fields */
|
||||||
|
|
||||||
/// Writes the faceted fields in the database.
|
/// Writes the faceted fields in the database.
|
||||||
pub(crate) fn put_faceted_fields(
|
// pub(crate) fn put_faceted_fields(
|
||||||
&self,
|
// &self,
|
||||||
wtxn: &mut RwTxn<'_>,
|
// wtxn: &mut RwTxn<'_>,
|
||||||
fields: &HashSet<String>,
|
// fields: &HashSet<String>,
|
||||||
) -> heed::Result<()> {
|
// ) -> heed::Result<()> {
|
||||||
self.main.remap_types::<Str, SerdeJson<_>>().put(
|
// self.main.remap_types::<Str, SerdeJson<_>>().put(
|
||||||
wtxn,
|
// wtxn,
|
||||||
main_key::HIDDEN_FACETED_FIELDS_KEY,
|
// main_key::HIDDEN_FACETED_FIELDS_KEY,
|
||||||
fields,
|
// fields,
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Returns true if the geo feature is activated.
|
/// Returns true if the geo feature is activated.
|
||||||
pub fn is_geo_activated(&self, rtxn: &RoTxn<'_>) -> Result<bool> {
|
pub fn is_geo_activated(&self, rtxn: &RoTxn<'_>) -> Result<bool> {
|
||||||
@ -892,25 +895,26 @@ impl Index {
|
|||||||
|
|
||||||
/// Returns true if the geo filtering feature is activated.
|
/// Returns true if the geo filtering feature is activated.
|
||||||
pub fn is_geo_filtering_activated(&self, rtxn: &RoTxn<'_>) -> Result<bool> {
|
pub fn is_geo_filtering_activated(&self, rtxn: &RoTxn<'_>) -> Result<bool> {
|
||||||
let geo_filter = self.filterable_fields(rtxn)?.iter().any(|field| field.has_geo());
|
let geo_filter =
|
||||||
|
self.filterable_attributes_rules(rtxn)?.iter().any(|field| field.has_geo());
|
||||||
Ok(geo_filter)
|
Ok(geo_filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the field ids of the fields that are filterable using the ordering operators or are sortable.
|
/// Returns the field ids of the fields that are filterable using the ordering operators or are sortable.
|
||||||
pub fn facet_leveled_field_ids(&self, rtxn: &RoTxn<'_>) -> Result<Vec<FieldId>> {
|
pub fn facet_leveled_field_ids(&self, rtxn: &RoTxn<'_>) -> Result<HashSet<FieldId>> {
|
||||||
let filterable_fields = self.filterable_fields(rtxn)?;
|
let filterable_fields = self.filterable_attributes_rules(rtxn)?;
|
||||||
let sortable_fields = self.sortable_fields(rtxn)?;
|
let sortable_fields = self.sortable_fields(rtxn)?;
|
||||||
let fields_ids_map = self.fields_ids_map(rtxn)?;
|
let fields_ids_map = self.fields_ids_map(rtxn)?;
|
||||||
|
|
||||||
let mut fields_ids = Vec::new();
|
let mut fields_ids = HashSet::new();
|
||||||
for (field_id, field_name) in fields_ids_map.iter() {
|
for (field_id, field_name) in fields_ids_map.iter() {
|
||||||
if match_pattern_by_features(field_name, &filterable_fields, &|features| {
|
if match_pattern_by_features(field_name, &filterable_fields, &|features| {
|
||||||
features.is_filterable_order()
|
features.is_filterable_order()
|
||||||
}) == PatternMatch::Match
|
}) == PatternMatch::Match
|
||||||
{
|
{
|
||||||
fields_ids.push(field_id);
|
fields_ids.insert(field_id);
|
||||||
} else if sortable_fields.contains(field_name) {
|
} else if sortable_fields.contains(field_name) {
|
||||||
fields_ids.push(field_id);
|
fields_ids.insert(field_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1778,7 +1782,7 @@ pub(crate) mod tests {
|
|||||||
use crate::vector::settings::{EmbedderSource, EmbeddingSettings};
|
use crate::vector::settings::{EmbedderSource, EmbeddingSettings};
|
||||||
use crate::vector::EmbeddingConfigs;
|
use crate::vector::EmbeddingConfigs;
|
||||||
use crate::{
|
use crate::{
|
||||||
db_snap, obkv_to_json, Filter, FilterableAttributesSettings, Index, Search, SearchResult,
|
db_snap, obkv_to_json, Filter, FilterableAttributesRule, Index, Search, SearchResult,
|
||||||
ThreadPoolNoAbortBuilder,
|
ThreadPoolNoAbortBuilder,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2209,7 +2213,7 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
RESERVED_GEO_FIELD_NAME.to_string(),
|
RESERVED_GEO_FIELD_NAME.to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -2319,7 +2323,7 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"doggo".to_string(),
|
"doggo".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -2363,7 +2367,7 @@ pub(crate) mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_primary_key("id".to_owned());
|
settings.set_primary_key("id".to_owned());
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"doggo".to_string(),
|
"doggo".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -2898,7 +2902,7 @@ pub(crate) mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_primary_key("id".to_string());
|
settings.set_primary_key("id".to_string());
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
RESERVED_GEO_FIELD_NAME.to_string(),
|
RESERVED_GEO_FIELD_NAME.to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -2934,7 +2938,7 @@ pub(crate) mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_primary_key("id".to_string());
|
settings.set_primary_key("id".to_string());
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
RESERVED_GEO_FIELD_NAME.to_string(),
|
RESERVED_GEO_FIELD_NAME.to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -2969,7 +2973,7 @@ pub(crate) mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_searchable_fields(vec![S("name")]);
|
settings.set_searchable_fields(vec![S("name")]);
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"age".to_string(),
|
"age".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -2993,7 +2997,7 @@ pub(crate) mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_searchable_fields(vec![S("name"), S("realName")]);
|
settings.set_searchable_fields(vec![S("name"), S("realName")]);
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"age".to_string(),
|
"age".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -3095,8 +3099,8 @@ pub(crate) mod tests {
|
|||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_searchable_fields(vec![S("_vectors"), S("_vectors.doggo")]);
|
settings.set_searchable_fields(vec![S("_vectors"), S("_vectors.doggo")]);
|
||||||
settings.set_filterable_fields(vec![
|
settings.set_filterable_fields(vec![
|
||||||
FilterableAttributesSettings::Field("_vectors".to_string()),
|
FilterableAttributesRule::Field("_vectors".to_string()),
|
||||||
FilterableAttributesSettings::Field("_vectors.doggo".to_string()),
|
FilterableAttributesRule::Field("_vectors.doggo".to_string()),
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -15,7 +15,7 @@ mod error;
|
|||||||
mod external_documents_ids;
|
mod external_documents_ids;
|
||||||
pub mod facet;
|
pub mod facet;
|
||||||
mod fields_ids_map;
|
mod fields_ids_map;
|
||||||
mod filterable_fields;
|
mod filterable_attributes_rules;
|
||||||
pub mod heed_codec;
|
pub mod heed_codec;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
mod localized_attributes_rules;
|
mod localized_attributes_rules;
|
||||||
@ -61,8 +61,8 @@ pub use self::error::{
|
|||||||
pub use self::external_documents_ids::ExternalDocumentsIds;
|
pub use self::external_documents_ids::ExternalDocumentsIds;
|
||||||
pub use self::fieldids_weights_map::FieldidsWeightsMap;
|
pub use self::fieldids_weights_map::FieldidsWeightsMap;
|
||||||
pub use self::fields_ids_map::{FieldsIdsMap, GlobalFieldsIdsMap};
|
pub use self::fields_ids_map::{FieldsIdsMap, GlobalFieldsIdsMap};
|
||||||
pub use self::filterable_fields::{
|
pub use self::filterable_attributes_rules::{
|
||||||
FilterableAttributesFeatures, FilterableAttributesPatterns, FilterableAttributesSettings,
|
FilterableAttributesFeatures, FilterableAttributesPatterns, FilterableAttributesRule,
|
||||||
};
|
};
|
||||||
pub use self::heed_codec::{
|
pub use self::heed_codec::{
|
||||||
BEU16StrCodec, BEU32StrCodec, BoRoaringBitmapCodec, BoRoaringBitmapLenCodec,
|
BEU16StrCodec, BEU32StrCodec, BoRoaringBitmapCodec, BoRoaringBitmapLenCodec,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
@ -9,9 +9,8 @@ use indexmap::IndexMap;
|
|||||||
use roaring::RoaringBitmap;
|
use roaring::RoaringBitmap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::error::UserError;
|
|
||||||
use crate::facet::FacetType;
|
use crate::facet::FacetType;
|
||||||
use crate::filterable_fields::{is_field_filterable, matching_field_names};
|
use crate::fields_ids_map::metadata::{FieldIdMapWithMetadata, Metadata, MetadataBuilder};
|
||||||
use crate::heed_codec::facet::{
|
use crate::heed_codec::facet::{
|
||||||
FacetGroupKeyCodec, FieldDocIdFacetF64Codec, FieldDocIdFacetStringCodec, OrderedF64Codec,
|
FacetGroupKeyCodec, FieldDocIdFacetF64Codec, FieldDocIdFacetStringCodec, OrderedF64Codec,
|
||||||
};
|
};
|
||||||
@ -19,7 +18,7 @@ use crate::heed_codec::{BytesRefCodec, StrRefCodec};
|
|||||||
use crate::search::facet::facet_distribution_iter::{
|
use crate::search::facet::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, FieldsIdsMap, Index, Result};
|
use crate::{FieldId, FilterableAttributesRule, 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.
|
||||||
@ -281,18 +280,22 @@ impl<'a> FacetDistribution<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_stats(&self) -> Result<BTreeMap<String, (f64, f64)>> {
|
pub fn compute_stats(&self) -> Result<BTreeMap<String, (f64, f64)>> {
|
||||||
let fields_ids_map = self.index.fields_ids_map(self.rtxn)?;
|
|
||||||
let candidates = if let Some(candidates) = self.candidates.clone() {
|
let candidates = if let Some(candidates) = self.candidates.clone() {
|
||||||
candidates
|
candidates
|
||||||
} else {
|
} else {
|
||||||
return Ok(Default::default());
|
return Ok(Default::default());
|
||||||
};
|
};
|
||||||
|
|
||||||
let fields = self.faceted_fields_names(&fields_ids_map)?;
|
let fields_ids_map = self.index.fields_ids_map(self.rtxn)?;
|
||||||
|
let fields_ids_map = FieldIdMapWithMetadata::new(
|
||||||
|
fields_ids_map,
|
||||||
|
MetadataBuilder::from_index(self.index, self.rtxn)?,
|
||||||
|
);
|
||||||
|
let filterable_attributes_rules = self.index.filterable_attributes_rules(self.rtxn)?;
|
||||||
|
|
||||||
let mut distribution = BTreeMap::new();
|
let mut distribution = BTreeMap::new();
|
||||||
for (fid, name) in fields_ids_map.iter() {
|
for (fid, name, metadata) in fields_ids_map.iter() {
|
||||||
if crate::is_faceted(name, &fields) {
|
if self.select_field(name, &metadata, &filterable_attributes_rules) {
|
||||||
let min_value = if let Some(min_value) = crate::search::facet::facet_min_value(
|
let min_value = if let Some(min_value) = crate::search::facet::facet_min_value(
|
||||||
self.index,
|
self.index,
|
||||||
self.rtxn,
|
self.rtxn,
|
||||||
@ -323,12 +326,15 @@ impl<'a> FacetDistribution<'a> {
|
|||||||
|
|
||||||
pub fn execute(&self) -> Result<BTreeMap<String, IndexMap<String, u64>>> {
|
pub fn execute(&self) -> Result<BTreeMap<String, IndexMap<String, u64>>> {
|
||||||
let fields_ids_map = self.index.fields_ids_map(self.rtxn)?;
|
let fields_ids_map = self.index.fields_ids_map(self.rtxn)?;
|
||||||
|
let fields_ids_map = FieldIdMapWithMetadata::new(
|
||||||
let fields = self.faceted_fields_names(&fields_ids_map)?;
|
fields_ids_map,
|
||||||
|
MetadataBuilder::from_index(self.index, self.rtxn)?,
|
||||||
|
);
|
||||||
|
let filterable_attributes_rules = self.index.filterable_attributes_rules(self.rtxn)?;
|
||||||
|
|
||||||
let mut distribution = BTreeMap::new();
|
let mut distribution = BTreeMap::new();
|
||||||
for (fid, name) in fields_ids_map.iter() {
|
for (fid, name, metadata) in fields_ids_map.iter() {
|
||||||
if crate::is_faceted(name, &fields) {
|
if self.select_field(name, &metadata, &filterable_attributes_rules) {
|
||||||
let order_by = self
|
let order_by = self
|
||||||
.facets
|
.facets
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -342,38 +348,21 @@ impl<'a> FacetDistribution<'a> {
|
|||||||
Ok(distribution)
|
Ok(distribution)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn faceted_fields_names(&self, fields_ids_map: &FieldsIdsMap) -> Result<Vec<String>> {
|
/// Select a field if it is faceted and in the facets.
|
||||||
/// TODO: @many: this is a bit of a mess, we should refactor it
|
fn select_field(
|
||||||
let filterable_fields = self.index.filterable_fields(self.rtxn)?;
|
&self,
|
||||||
let fields = match &self.facets {
|
name: &str,
|
||||||
Some(facets) => {
|
metadata: &Metadata,
|
||||||
let invalid_fields: HashSet<_> = facets
|
filterable_attributes_rules: &[FilterableAttributesRule],
|
||||||
.iter()
|
) -> bool {
|
||||||
.map(|(name, _)| name)
|
if !metadata.is_faceted(filterable_attributes_rules) {
|
||||||
.filter(|facet| !is_field_filterable(facet, &filterable_fields))
|
return false;
|
||||||
.collect();
|
}
|
||||||
if !invalid_fields.is_empty() {
|
|
||||||
let valid_facets_name =
|
|
||||||
matching_field_names(&filterable_fields, &fields_ids_map);
|
|
||||||
return Err(UserError::InvalidFacetsDistribution {
|
|
||||||
invalid_facets_name: invalid_fields.into_iter().cloned().collect(),
|
|
||||||
valid_facets_name: valid_facets_name
|
|
||||||
.into_iter()
|
|
||||||
.map(String::from)
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
.into());
|
|
||||||
} else {
|
|
||||||
facets.iter().map(|(name, _)| name).cloned().collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => matching_field_names(&filterable_fields, &fields_ids_map)
|
|
||||||
.into_iter()
|
|
||||||
.map(String::from)
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(fields)
|
match &self.facets {
|
||||||
|
Some(facets) => facets.contains_key(name),
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,7 +394,7 @@ mod tests {
|
|||||||
|
|
||||||
use crate::documents::mmap_from_objects;
|
use crate::documents::mmap_from_objects;
|
||||||
use crate::index::tests::TempIndex;
|
use crate::index::tests::TempIndex;
|
||||||
use crate::{milli_snap, FacetDistribution, FilterableAttributesSettings, OrderBy};
|
use crate::{milli_snap, FacetDistribution, FilterableAttributesRule, OrderBy};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn few_candidates_few_facet_values() {
|
fn few_candidates_few_facet_values() {
|
||||||
@ -416,8 +405,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S("colour"))])
|
||||||
.set_filterable_fields(vec![FilterableAttributesSettings::Field(S("colour"))])
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -490,8 +478,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S("colour"))])
|
||||||
.set_filterable_fields(vec![FilterableAttributesSettings::Field(S("colour"))])
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -578,8 +565,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S("colour"))])
|
||||||
.set_filterable_fields(vec![FilterableAttributesSettings::Field(S("colour"))])
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -640,8 +626,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S("colour"))])
|
||||||
.set_filterable_fields(vec![FilterableAttributesSettings::Field(S("colour"))])
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -694,8 +679,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S("colour"))])
|
||||||
.set_filterable_fields(vec![FilterableAttributesSettings::Field(S("colour"))])
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -748,8 +732,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S("colour"))])
|
||||||
.set_filterable_fields(vec![FilterableAttributesSettings::Field(S("colour"))])
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -802,8 +785,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S("colour"))])
|
||||||
.set_filterable_fields(vec![FilterableAttributesSettings::Field(S("colour"))])
|
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use serde_json::Value;
|
|||||||
use super::facet_range_search;
|
use super::facet_range_search;
|
||||||
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
||||||
use crate::error::{Error, UserError};
|
use crate::error::{Error, UserError};
|
||||||
use crate::filterable_fields::{
|
use crate::filterable_attributes_rules::{
|
||||||
filtered_matching_field_names, is_field_filterable, matching_features,
|
filtered_matching_field_names, is_field_filterable, matching_features,
|
||||||
};
|
};
|
||||||
use crate::heed_codec::facet::{
|
use crate::heed_codec::facet::{
|
||||||
@ -21,7 +21,7 @@ use crate::heed_codec::facet::{
|
|||||||
use crate::index::db_name::FACET_ID_STRING_DOCIDS;
|
use crate::index::db_name::FACET_ID_STRING_DOCIDS;
|
||||||
use crate::{
|
use crate::{
|
||||||
distance_between_two_points, lat_lng_to_xyz, FieldId, FilterableAttributesFeatures,
|
distance_between_two_points, lat_lng_to_xyz, FieldId, FilterableAttributesFeatures,
|
||||||
FilterableAttributesSettings, Index, InternalError, Result, SerializationError,
|
FilterableAttributesRule, Index, InternalError, Result, SerializationError,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The maximum number of filters the filter AST can process.
|
/// The maximum number of filters the filter AST can process.
|
||||||
@ -233,22 +233,22 @@ impl<'a> Filter<'a> {
|
|||||||
impl<'a> Filter<'a> {
|
impl<'a> Filter<'a> {
|
||||||
pub fn evaluate(&self, rtxn: &heed::RoTxn<'_>, index: &Index) -> Result<RoaringBitmap> {
|
pub fn evaluate(&self, rtxn: &heed::RoTxn<'_>, index: &Index) -> Result<RoaringBitmap> {
|
||||||
// to avoid doing this for each recursive call we're going to do it ONCE ahead of time
|
// to avoid doing this for each recursive call we're going to do it ONCE ahead of time
|
||||||
let filterable_fields = index.filterable_fields(rtxn)?;
|
let filterable_attributes_rules = index.filterable_attributes_rules(rtxn)?;
|
||||||
for fid in self.condition.fids(MAX_FILTER_DEPTH) {
|
for fid in self.condition.fids(MAX_FILTER_DEPTH) {
|
||||||
let attribute = fid.value();
|
let attribute = fid.value();
|
||||||
if !is_field_filterable(attribute, &filterable_fields) {
|
if !is_field_filterable(attribute, &filterable_attributes_rules) {
|
||||||
let fields_ids_map = index.fields_ids_map(rtxn)?;
|
let fields_ids_map = index.fields_ids_map(rtxn)?;
|
||||||
return Err(fid.as_external_error(FilterError::AttributeNotFilterable {
|
return Err(fid.as_external_error(FilterError::AttributeNotFilterable {
|
||||||
attribute,
|
attribute,
|
||||||
filterable_fields: filtered_matching_field_names(
|
filterable_fields: filtered_matching_field_names(
|
||||||
&filterable_fields,
|
&filterable_attributes_rules,
|
||||||
&fields_ids_map,
|
&fields_ids_map,
|
||||||
&|features| features.is_filterable(),
|
&|features| features.is_filterable(),
|
||||||
),
|
),
|
||||||
}))?;
|
}))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.inner_evaluate(rtxn, index, &filterable_fields, None)
|
self.inner_evaluate(rtxn, index, &filterable_attributes_rules, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_operator(
|
fn evaluate_operator(
|
||||||
@ -278,6 +278,18 @@ impl<'a> Filter<'a> {
|
|||||||
/// TODO produce an dedicated error for this
|
/// TODO produce an dedicated error for this
|
||||||
todo!("filtering on non-ordered fields is not supported, return an error")
|
todo!("filtering on non-ordered fields is not supported, return an error")
|
||||||
}
|
}
|
||||||
|
Condition::Empty if !features.is_filterable_empty() => {
|
||||||
|
/// TODO produce an dedicated error for this
|
||||||
|
todo!("filtering on non-empty fields is not supported, return an error")
|
||||||
|
}
|
||||||
|
Condition::Null if !features.is_filterable_null() => {
|
||||||
|
/// TODO produce an dedicated error for this
|
||||||
|
todo!("filtering on non-null fields is not supported, return an error")
|
||||||
|
}
|
||||||
|
Condition::Exists if !features.is_filterable_exists() => {
|
||||||
|
/// TODO produce an dedicated error for this
|
||||||
|
todo!("filtering on non-exists fields is not supported, return an error")
|
||||||
|
}
|
||||||
Condition::GreaterThan(val) => {
|
Condition::GreaterThan(val) => {
|
||||||
(Excluded(val.parse_finite_float()?), Included(f64::MAX))
|
(Excluded(val.parse_finite_float()?), Included(f64::MAX))
|
||||||
}
|
}
|
||||||
@ -430,7 +442,7 @@ impl<'a> Filter<'a> {
|
|||||||
&self,
|
&self,
|
||||||
rtxn: &heed::RoTxn<'_>,
|
rtxn: &heed::RoTxn<'_>,
|
||||||
index: &Index,
|
index: &Index,
|
||||||
filterable_fields: &[FilterableAttributesSettings],
|
filterable_fields: &[FilterableAttributesRule],
|
||||||
universe: Option<&RoaringBitmap>,
|
universe: Option<&RoaringBitmap>,
|
||||||
) -> Result<RoaringBitmap> {
|
) -> Result<RoaringBitmap> {
|
||||||
if universe.map_or(false, |u| u.is_empty()) {
|
if universe.map_or(false, |u| u.is_empty()) {
|
||||||
@ -742,7 +754,7 @@ mod tests {
|
|||||||
|
|
||||||
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
||||||
use crate::index::tests::TempIndex;
|
use crate::index::tests::TempIndex;
|
||||||
use crate::{Filter, FilterableAttributesSettings};
|
use crate::{Filter, FilterableAttributesRule};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_db() {
|
fn empty_db() {
|
||||||
@ -750,7 +762,7 @@ mod tests {
|
|||||||
//Set the filterable fields to be the channel.
|
//Set the filterable fields to be the channel.
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"PrIcE".to_string(),
|
"PrIcE".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -856,7 +868,7 @@ mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_searchable_fields(vec![S("title")]);
|
settings.set_searchable_fields(vec![S("title")]);
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"title".to_string(),
|
"title".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -924,7 +936,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"monitor_diagonal".to_string(),
|
"monitor_diagonal".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -957,7 +969,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(S(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(S(
|
||||||
RESERVED_GEO_FIELD_NAME,
|
RESERVED_GEO_FIELD_NAME,
|
||||||
))]);
|
))]);
|
||||||
})
|
})
|
||||||
@ -1007,8 +1019,8 @@ mod tests {
|
|||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_searchable_fields(vec![S(RESERVED_GEO_FIELD_NAME), S("price")]); // to keep the fields order
|
settings.set_searchable_fields(vec![S(RESERVED_GEO_FIELD_NAME), S("price")]); // to keep the fields order
|
||||||
settings.set_filterable_fields(vec![
|
settings.set_filterable_fields(vec![
|
||||||
FilterableAttributesSettings::Field(S(RESERVED_GEO_FIELD_NAME)),
|
FilterableAttributesRule::Field(S(RESERVED_GEO_FIELD_NAME)),
|
||||||
FilterableAttributesSettings::Field("price".to_string()),
|
FilterableAttributesRule::Field("price".to_string()),
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1060,8 +1072,8 @@ mod tests {
|
|||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_searchable_fields(vec![S(RESERVED_GEO_FIELD_NAME), S("price")]); // to keep the fields order
|
settings.set_searchable_fields(vec![S(RESERVED_GEO_FIELD_NAME), S("price")]); // to keep the fields order
|
||||||
settings.set_filterable_fields(vec![
|
settings.set_filterable_fields(vec![
|
||||||
FilterableAttributesSettings::Field(S(RESERVED_GEO_FIELD_NAME)),
|
FilterableAttributesRule::Field(S(RESERVED_GEO_FIELD_NAME)),
|
||||||
FilterableAttributesSettings::Field("price".to_string()),
|
FilterableAttributesRule::Field("price".to_string()),
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1172,7 +1184,7 @@ mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_searchable_fields(vec![S("price")]); // to keep the fields order
|
settings.set_searchable_fields(vec![S("price")]); // to keep the fields order
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"price".to_string(),
|
"price".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -1231,9 +1243,9 @@ mod tests {
|
|||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_primary_key("id".to_owned());
|
settings.set_primary_key("id".to_owned());
|
||||||
settings.set_filterable_fields(vec![
|
settings.set_filterable_fields(vec![
|
||||||
FilterableAttributesSettings::Field("id".to_string()),
|
FilterableAttributesRule::Field("id".to_string()),
|
||||||
FilterableAttributesSettings::Field("one".to_string()),
|
FilterableAttributesRule::Field("one".to_string()),
|
||||||
FilterableAttributesSettings::Field("two".to_string()),
|
FilterableAttributesRule::Field("two".to_string()),
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -10,7 +10,7 @@ use roaring::RoaringBitmap;
|
|||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use crate::error::UserError;
|
use crate::error::UserError;
|
||||||
use crate::filterable_fields::{is_field_filterable, matching_field_names};
|
use crate::filterable_attributes_rules::{is_field_filterable, matching_field_names};
|
||||||
use crate::heed_codec::facet::{FacetGroupKey, FacetGroupValue};
|
use crate::heed_codec::facet::{FacetGroupKey, FacetGroupValue};
|
||||||
use crate::search::build_dfa;
|
use crate::search::build_dfa;
|
||||||
use crate::{DocumentId, FieldId, OrderBy, Result, Search};
|
use crate::{DocumentId, FieldId, OrderBy, Result, Search};
|
||||||
@ -74,7 +74,7 @@ impl<'a> SearchForFacetValues<'a> {
|
|||||||
let index = self.search_query.index;
|
let index = self.search_query.index;
|
||||||
let rtxn = self.search_query.rtxn;
|
let rtxn = self.search_query.rtxn;
|
||||||
|
|
||||||
let filterable_fields = index.filterable_fields(rtxn)?;
|
let filterable_fields = index.filterable_attributes_rules(rtxn)?;
|
||||||
if !is_field_filterable(&self.facet, &filterable_fields) {
|
if !is_field_filterable(&self.facet, &filterable_fields) {
|
||||||
let fields_ids_map = index.fields_ids_map(rtxn)?;
|
let fields_ids_map = index.fields_ids_map(rtxn)?;
|
||||||
let matching_field_names = matching_field_names(&filterable_fields, &fields_ids_map);
|
let matching_field_names = matching_field_names(&filterable_fields, &fields_ids_map);
|
||||||
|
@ -9,7 +9,7 @@ use roaring::bitmap::RoaringBitmap;
|
|||||||
pub use self::facet::{FacetDistribution, Filter, OrderBy, DEFAULT_VALUES_PER_FACET};
|
pub use self::facet::{FacetDistribution, Filter, OrderBy, DEFAULT_VALUES_PER_FACET};
|
||||||
pub use self::new::matches::{FormatOptions, MatchBounds, MatcherBuilder, MatchingWords};
|
pub use self::new::matches::{FormatOptions, MatchBounds, MatcherBuilder, MatchingWords};
|
||||||
use self::new::{execute_vector_search, PartialSearchResult};
|
use self::new::{execute_vector_search, PartialSearchResult};
|
||||||
use crate::filterable_fields::{is_field_filterable, matching_field_names};
|
use crate::filterable_attributes_rules::{is_field_filterable, matching_field_names};
|
||||||
use crate::score_details::{ScoreDetails, ScoringStrategy};
|
use crate::score_details::{ScoreDetails, ScoringStrategy};
|
||||||
use crate::vector::Embedder;
|
use crate::vector::Embedder;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -188,7 +188,7 @@ impl<'a> Search<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(distinct) = &self.distinct {
|
if let Some(distinct) = &self.distinct {
|
||||||
let filterable_fields = ctx.index.filterable_fields(ctx.txn)?;
|
let filterable_fields = ctx.index.filterable_attributes_rules(ctx.txn)?;
|
||||||
// check if the distinct field is in the filterable fields
|
// check if the distinct field is in the filterable fields
|
||||||
if !is_field_filterable(distinct, &filterable_fields) {
|
if !is_field_filterable(distinct, &filterable_fields) {
|
||||||
// if not, remove the hidden fields from the filterable fields to generate the error message
|
// if not, remove the hidden fields from the filterable fields to generate the error message
|
||||||
|
@ -9,7 +9,7 @@ use meili_snap::snapshot;
|
|||||||
|
|
||||||
use crate::index::tests::TempIndex;
|
use crate::index::tests::TempIndex;
|
||||||
use crate::score_details::{ScoreDetails, ScoringStrategy};
|
use crate::score_details::{ScoreDetails, ScoringStrategy};
|
||||||
use crate::{Criterion, Filter, FilterableAttributesSettings, Search, TimeBudget};
|
use crate::{Criterion, Filter, FilterableAttributesRule, Search, TimeBudget};
|
||||||
|
|
||||||
fn create_index() -> TempIndex {
|
fn create_index() -> TempIndex {
|
||||||
let index = TempIndex::new();
|
let index = TempIndex::new();
|
||||||
@ -18,7 +18,7 @@ fn create_index() -> TempIndex {
|
|||||||
.update_settings(|s| {
|
.update_settings(|s| {
|
||||||
s.set_primary_key("id".to_owned());
|
s.set_primary_key("id".to_owned());
|
||||||
s.set_searchable_fields(vec!["text".to_owned()]);
|
s.set_searchable_fields(vec!["text".to_owned()]);
|
||||||
s.set_filterable_fields(vec![FilterableAttributesSettings::Field("id".to_owned())]);
|
s.set_filterable_fields(vec![FilterableAttributesRule::Field("id".to_owned())]);
|
||||||
s.set_criteria(vec![Criterion::Words, Criterion::Typo]);
|
s.set_criteria(vec![Criterion::Words, Criterion::Typo]);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -20,7 +20,7 @@ use maplit::hashset;
|
|||||||
use super::collect_field_values;
|
use super::collect_field_values;
|
||||||
use crate::index::tests::TempIndex;
|
use crate::index::tests::TempIndex;
|
||||||
use crate::{
|
use crate::{
|
||||||
AscDesc, Criterion, FilterableAttributesSettings, Index, Member, Search, SearchResult,
|
AscDesc, Criterion, FilterableAttributesRule, Index, Member, Search, SearchResult,
|
||||||
TermsMatchingStrategy,
|
TermsMatchingStrategy,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ fn test_distinct_placeholder_no_ranking_rules() {
|
|||||||
// Set the letter as filterable and unset the distinct attribute.
|
// Set the letter as filterable and unset the distinct attribute.
|
||||||
index
|
index
|
||||||
.update_settings(|s| {
|
.update_settings(|s| {
|
||||||
s.set_filterable_fields(vec![FilterableAttributesSettings::Field("letter".to_owned())]);
|
s.set_filterable_fields(vec![FilterableAttributesRule::Field("letter".to_owned())]);
|
||||||
s.reset_distinct_field();
|
s.reset_distinct_field();
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -9,7 +9,7 @@ use crate::progress::Progress;
|
|||||||
use crate::update::new::indexer;
|
use crate::update::new::indexer;
|
||||||
use crate::update::{IndexDocumentsMethod, IndexerConfig, Settings};
|
use crate::update::{IndexDocumentsMethod, IndexerConfig, Settings};
|
||||||
use crate::vector::EmbeddingConfigs;
|
use crate::vector::EmbeddingConfigs;
|
||||||
use crate::{db_snap, Criterion, FilterableAttributesSettings, Index};
|
use crate::{db_snap, Criterion, FilterableAttributesRule, Index};
|
||||||
pub const CONTENT: &str = include_str!("../../../../tests/assets/test_set.ndjson");
|
pub const CONTENT: &str = include_str!("../../../../tests/assets/test_set.ndjson");
|
||||||
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
||||||
|
|
||||||
@ -26,12 +26,12 @@ pub fn setup_search_index_with_criteria(criteria: &[Criterion]) -> Index {
|
|||||||
|
|
||||||
builder.set_criteria(criteria.to_vec());
|
builder.set_criteria(criteria.to_vec());
|
||||||
builder.set_filterable_fields(vec![
|
builder.set_filterable_fields(vec![
|
||||||
FilterableAttributesSettings::Field(S("tag")),
|
FilterableAttributesRule::Field(S("tag")),
|
||||||
FilterableAttributesSettings::Field(S("asc_desc_rank")),
|
FilterableAttributesRule::Field(S("asc_desc_rank")),
|
||||||
FilterableAttributesSettings::Field(S(RESERVED_GEO_FIELD_NAME)),
|
FilterableAttributesRule::Field(S(RESERVED_GEO_FIELD_NAME)),
|
||||||
FilterableAttributesSettings::Field(S("opt1")),
|
FilterableAttributesRule::Field(S("opt1")),
|
||||||
FilterableAttributesSettings::Field(S("opt1.opt2")),
|
FilterableAttributesRule::Field(S("opt1.opt2")),
|
||||||
FilterableAttributesSettings::Field(S("tag_in")),
|
FilterableAttributesRule::Field(S("tag_in")),
|
||||||
]);
|
]);
|
||||||
builder.set_sortable_fields(hashset! {
|
builder.set_sortable_fields(hashset! {
|
||||||
S("tag"),
|
S("tag"),
|
||||||
|
@ -386,7 +386,7 @@ pub fn snap_settings(index: &Index) -> String {
|
|||||||
write_setting_to_snap!(criteria);
|
write_setting_to_snap!(criteria);
|
||||||
write_setting_to_snap!(displayed_fields);
|
write_setting_to_snap!(displayed_fields);
|
||||||
write_setting_to_snap!(distinct_field);
|
write_setting_to_snap!(distinct_field);
|
||||||
write_setting_to_snap!(filterable_fields);
|
write_setting_to_snap!(filterable_attributes_rules);
|
||||||
write_setting_to_snap!(sortable_fields);
|
write_setting_to_snap!(sortable_fields);
|
||||||
write_setting_to_snap!(synonyms);
|
write_setting_to_snap!(synonyms);
|
||||||
write_setting_to_snap!(authorize_typos);
|
write_setting_to_snap!(authorize_typos);
|
||||||
|
@ -374,7 +374,7 @@ mod tests {
|
|||||||
use crate::heed_codec::StrRefCodec;
|
use crate::heed_codec::StrRefCodec;
|
||||||
use crate::index::tests::TempIndex;
|
use crate::index::tests::TempIndex;
|
||||||
use crate::update::facet::test_helpers::{ordered_string, FacetIndex};
|
use crate::update::facet::test_helpers::{ordered_string, FacetIndex};
|
||||||
use crate::{db_snap, milli_snap, FilterableAttributesSettings};
|
use crate::{db_snap, milli_snap, FilterableAttributesRule};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn insert() {
|
fn insert() {
|
||||||
@ -474,7 +474,7 @@ mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_primary_key("id".to_owned());
|
settings.set_primary_key("id".to_owned());
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"id".to_string(),
|
"id".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
|
@ -765,14 +765,14 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
use crate::constants::RESERVED_GEO_FIELD_NAME;
|
||||||
use crate::documents::mmap_from_objects;
|
use crate::documents::mmap_from_objects;
|
||||||
use crate::filterable_fields::filtered_matching_field_names;
|
use crate::filterable_attributes_rules::filtered_matching_field_names;
|
||||||
use crate::index::tests::TempIndex;
|
use crate::index::tests::TempIndex;
|
||||||
use crate::index::IndexEmbeddingConfig;
|
use crate::index::IndexEmbeddingConfig;
|
||||||
use crate::progress::Progress;
|
use crate::progress::Progress;
|
||||||
use crate::search::TermsMatchingStrategy;
|
use crate::search::TermsMatchingStrategy;
|
||||||
use crate::update::new::indexer;
|
use crate::update::new::indexer;
|
||||||
use crate::update::Setting;
|
use crate::update::Setting;
|
||||||
use crate::{db_snap, Filter, FilterableAttributesSettings, Search, UserError};
|
use crate::{db_snap, Filter, FilterableAttributesRule, Search, UserError};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_document_replacement() {
|
fn simple_document_replacement() {
|
||||||
@ -1002,7 +1002,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
RESERVED_GEO_FIELD_NAME.to_string(),
|
RESERVED_GEO_FIELD_NAME.to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -1016,7 +1016,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
RESERVED_GEO_FIELD_NAME.to_string(),
|
RESERVED_GEO_FIELD_NAME.to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -1235,9 +1235,9 @@ mod tests {
|
|||||||
settings.set_searchable_fields(searchable_fields);
|
settings.set_searchable_fields(searchable_fields);
|
||||||
|
|
||||||
let faceted_fields = vec![
|
let faceted_fields = vec![
|
||||||
FilterableAttributesSettings::Field("title".to_string()),
|
FilterableAttributesRule::Field("title".to_string()),
|
||||||
FilterableAttributesSettings::Field("nested.object".to_string()),
|
FilterableAttributesRule::Field("nested.object".to_string()),
|
||||||
FilterableAttributesSettings::Field("nested.machin".to_string()),
|
FilterableAttributesRule::Field("nested.machin".to_string()),
|
||||||
];
|
];
|
||||||
settings.set_filterable_fields(faceted_fields);
|
settings.set_filterable_fields(faceted_fields);
|
||||||
})
|
})
|
||||||
@ -1245,7 +1245,7 @@ mod tests {
|
|||||||
|
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
|
|
||||||
let filterable_fields = index.filterable_fields(&rtxn).unwrap();
|
let filterable_fields = index.filterable_attributes_rules(&rtxn).unwrap();
|
||||||
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
||||||
let facets =
|
let facets =
|
||||||
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
||||||
@ -1447,7 +1447,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"dog".to_string(),
|
"dog".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -1468,7 +1468,7 @@ mod tests {
|
|||||||
|
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
|
|
||||||
let filterable_fields = index.filterable_fields(&rtxn).unwrap();
|
let filterable_fields = index.filterable_attributes_rules(&rtxn).unwrap();
|
||||||
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
||||||
let facets =
|
let facets =
|
||||||
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
||||||
@ -1496,7 +1496,7 @@ mod tests {
|
|||||||
|
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
|
|
||||||
let filterable_fields = index.filterable_fields(&rtxn).unwrap();
|
let filterable_fields = index.filterable_attributes_rules(&rtxn).unwrap();
|
||||||
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
||||||
let facets =
|
let facets =
|
||||||
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
||||||
@ -1527,7 +1527,7 @@ mod tests {
|
|||||||
|
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
|
|
||||||
let filterable_fields = index.filterable_fields(&rtxn).unwrap();
|
let filterable_fields = index.filterable_attributes_rules(&rtxn).unwrap();
|
||||||
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
||||||
let facets =
|
let facets =
|
||||||
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
||||||
@ -1743,7 +1743,7 @@ mod tests {
|
|||||||
|
|
||||||
let check_ok = |index: &Index| {
|
let check_ok = |index: &Index| {
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
let filterable_fields = index.filterable_fields(&rtxn).unwrap();
|
let filterable_fields = index.filterable_attributes_rules(&rtxn).unwrap();
|
||||||
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
||||||
let facets =
|
let facets =
|
||||||
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
||||||
@ -1769,7 +1769,7 @@ mod tests {
|
|||||||
assert_eq!(bitmap_colour_blue.into_iter().collect::<Vec<_>>(), vec![7]);
|
assert_eq!(bitmap_colour_blue.into_iter().collect::<Vec<_>>(), vec![7]);
|
||||||
};
|
};
|
||||||
|
|
||||||
let faceted_fields = vec![FilterableAttributesSettings::Field("colour".to_string())];
|
let faceted_fields = vec![FilterableAttributesRule::Field("colour".to_string())];
|
||||||
|
|
||||||
let index = TempIndex::new();
|
let index = TempIndex::new();
|
||||||
index.add_documents(content()).unwrap();
|
index.add_documents(content()).unwrap();
|
||||||
@ -1854,7 +1854,7 @@ mod tests {
|
|||||||
|
|
||||||
let check_ok = |index: &Index| {
|
let check_ok = |index: &Index| {
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
let filterable_fields = index.filterable_fields(&rtxn).unwrap();
|
let filterable_fields = index.filterable_attributes_rules(&rtxn).unwrap();
|
||||||
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
||||||
let facets =
|
let facets =
|
||||||
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
||||||
@ -1880,7 +1880,7 @@ mod tests {
|
|||||||
assert_eq!(bitmap_colour_blue.into_iter().collect::<Vec<_>>(), vec![3]);
|
assert_eq!(bitmap_colour_blue.into_iter().collect::<Vec<_>>(), vec![3]);
|
||||||
};
|
};
|
||||||
|
|
||||||
let faceted_fields = vec![FilterableAttributesSettings::Field("colour".to_string())];
|
let faceted_fields = vec![FilterableAttributesRule::Field("colour".to_string())];
|
||||||
|
|
||||||
let index = TempIndex::new();
|
let index = TempIndex::new();
|
||||||
index.add_documents(content()).unwrap();
|
index.add_documents(content()).unwrap();
|
||||||
@ -1923,7 +1923,7 @@ mod tests {
|
|||||||
|
|
||||||
let check_ok = |index: &Index| {
|
let check_ok = |index: &Index| {
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
let filterable_fields = index.filterable_fields(&rtxn).unwrap();
|
let filterable_fields = index.filterable_attributes_rules(&rtxn).unwrap();
|
||||||
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
let fields_ids_map = index.fields_ids_map(&rtxn).unwrap();
|
||||||
let facets =
|
let facets =
|
||||||
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
filtered_matching_field_names(&filterable_fields, &fields_ids_map, &|features| {
|
||||||
@ -1948,7 +1948,7 @@ mod tests {
|
|||||||
assert_eq!(bitmap_tags_blue.into_iter().collect::<Vec<_>>(), vec![12]);
|
assert_eq!(bitmap_tags_blue.into_iter().collect::<Vec<_>>(), vec![12]);
|
||||||
};
|
};
|
||||||
|
|
||||||
let faceted_fields = vec![FilterableAttributesSettings::Field("tags".to_string())];
|
let faceted_fields = vec![FilterableAttributesRule::Field("tags".to_string())];
|
||||||
|
|
||||||
let index = TempIndex::new();
|
let index = TempIndex::new();
|
||||||
index.add_documents(content()).unwrap();
|
index.add_documents(content()).unwrap();
|
||||||
@ -2132,7 +2132,7 @@ mod tests {
|
|||||||
|
|
||||||
index
|
index
|
||||||
.update_settings(|settings| {
|
.update_settings(|settings| {
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
"title".to_string(),
|
"title".to_string(),
|
||||||
)]);
|
)]);
|
||||||
})
|
})
|
||||||
@ -2990,8 +2990,8 @@ mod tests {
|
|||||||
.update_settings_using_wtxn(&mut wtxn, |settings| {
|
.update_settings_using_wtxn(&mut wtxn, |settings| {
|
||||||
settings.set_primary_key(S("docid"));
|
settings.set_primary_key(S("docid"));
|
||||||
settings.set_filterable_fields(vec![
|
settings.set_filterable_fields(vec![
|
||||||
FilterableAttributesSettings::Field("label".to_string()),
|
FilterableAttributesRule::Field("label".to_string()),
|
||||||
FilterableAttributesSettings::Field("label2".to_string()),
|
FilterableAttributesRule::Field("label2".to_string()),
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -3171,7 +3171,7 @@ mod tests {
|
|||||||
index
|
index
|
||||||
.update_settings_using_wtxn(&mut wtxn, |settings| {
|
.update_settings_using_wtxn(&mut wtxn, |settings| {
|
||||||
settings.set_primary_key(S("id"));
|
settings.set_primary_key(S("id"));
|
||||||
settings.set_filterable_fields(vec![FilterableAttributesSettings::Field(
|
settings.set_filterable_fields(vec![FilterableAttributesRule::Field(
|
||||||
RESERVED_GEO_FIELD_NAME.to_string(),
|
RESERVED_GEO_FIELD_NAME.to_string(),
|
||||||
)]);
|
)]);
|
||||||
settings.set_sortable_fields(hashset!(S(RESERVED_GEO_FIELD_NAME)));
|
settings.set_sortable_fields(hashset!(S(RESERVED_GEO_FIELD_NAME)));
|
||||||
|
@ -24,7 +24,7 @@ use crate::update::new::thread_local::{FullySend, ThreadLocal};
|
|||||||
use crate::update::new::DocumentChange;
|
use crate::update::new::DocumentChange;
|
||||||
use crate::update::GrenadParameters;
|
use crate::update::GrenadParameters;
|
||||||
use crate::{
|
use crate::{
|
||||||
DocumentId, FieldId, FilterableAttributesFeatures, FilterableAttributesSettings, Result,
|
DocumentId, FieldId, FilterableAttributesFeatures, FilterableAttributesRule, Result,
|
||||||
MAX_FACET_VALUE_LENGTH,
|
MAX_FACET_VALUE_LENGTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ pub struct FacetedExtractorData<'a, 'b> {
|
|||||||
sender: &'a FieldIdDocidFacetSender<'a, 'b>,
|
sender: &'a FieldIdDocidFacetSender<'a, 'b>,
|
||||||
grenad_parameters: &'a GrenadParameters,
|
grenad_parameters: &'a GrenadParameters,
|
||||||
buckets: usize,
|
buckets: usize,
|
||||||
filterable_attributes: Vec<FilterableAttributesSettings>,
|
filterable_attributes: Vec<FilterableAttributesRule>,
|
||||||
sortable_fields: HashSet<String>,
|
sortable_fields: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ pub struct FacetedDocidsExtractor;
|
|||||||
impl FacetedDocidsExtractor {
|
impl FacetedDocidsExtractor {
|
||||||
fn extract_document_change(
|
fn extract_document_change(
|
||||||
context: &DocumentChangeContext<RefCell<BalancedCaches>>,
|
context: &DocumentChangeContext<RefCell<BalancedCaches>>,
|
||||||
filterable_attributes: &[FilterableAttributesSettings],
|
filterable_attributes: &[FilterableAttributesRule],
|
||||||
sortable_fields: &HashSet<String>,
|
sortable_fields: &HashSet<String>,
|
||||||
document_change: DocumentChange,
|
document_change: DocumentChange,
|
||||||
sender: &FieldIdDocidFacetSender,
|
sender: &FieldIdDocidFacetSender,
|
||||||
@ -424,7 +424,7 @@ impl FacetedDocidsExtractor {
|
|||||||
{
|
{
|
||||||
let index = indexing_context.index;
|
let index = indexing_context.index;
|
||||||
let rtxn = index.read_txn()?;
|
let rtxn = index.read_txn()?;
|
||||||
let filterable_attributes = index.filterable_fields(&rtxn)?;
|
let filterable_attributes = index.filterable_attributes_rules(&rtxn)?;
|
||||||
let sortable_fields = index.sortable_fields(&rtxn)?;
|
let sortable_fields = index.sortable_fields(&rtxn)?;
|
||||||
let datastore = ThreadLocal::new();
|
let datastore = ThreadLocal::new();
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ impl GeoExtractor {
|
|||||||
grenad_parameters: GrenadParameters,
|
grenad_parameters: GrenadParameters,
|
||||||
) -> Result<Option<Self>> {
|
) -> Result<Option<Self>> {
|
||||||
if index.is_geo_activated(rtxn)? {
|
if index.is_geo_activated(rtxn)? {
|
||||||
Ok(Some(GeoExtractor { grenad_parameters }))
|
Ok(Some(GeoExtractor {filterable_attributes_ruless }))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@ use crate::heed_codec::facet::FacetGroupKey;
|
|||||||
use crate::update::del_add::{DelAdd, KvWriterDelAdd};
|
use crate::update::del_add::{DelAdd, KvWriterDelAdd};
|
||||||
use crate::update::{create_sorter, MergeDeladdBtreesetString};
|
use crate::update::{create_sorter, MergeDeladdBtreesetString};
|
||||||
use crate::{
|
use crate::{
|
||||||
BEU16StrCodec, FieldId, GlobalFieldsIdsMap, Index, LocalizedAttributesRule, Result,
|
BEU16StrCodec, FieldId, FieldIdMapMissingEntry, FilterableAttributesFeatures,
|
||||||
MAX_FACET_VALUE_LENGTH,
|
FilterableAttributesRule, GlobalFieldsIdsMap, Index, InternalError, LocalizedAttributesRule,
|
||||||
|
Result, MAX_FACET_VALUE_LENGTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct FacetSearchBuilder<'indexer> {
|
pub struct FacetSearchBuilder<'indexer> {
|
||||||
@ -23,6 +24,7 @@ pub struct FacetSearchBuilder<'indexer> {
|
|||||||
normalized_facet_string_docids_sorter: Sorter<MergeDeladdBtreesetString>,
|
normalized_facet_string_docids_sorter: Sorter<MergeDeladdBtreesetString>,
|
||||||
global_fields_ids_map: GlobalFieldsIdsMap<'indexer>,
|
global_fields_ids_map: GlobalFieldsIdsMap<'indexer>,
|
||||||
localized_attributes_rules: Vec<LocalizedAttributesRule>,
|
localized_attributes_rules: Vec<LocalizedAttributesRule>,
|
||||||
|
filterable_attributes_rules: Vec<FilterableAttributesRule>,
|
||||||
// Buffered data below
|
// Buffered data below
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
localized_field_ids: HashMap<FieldId, Option<Vec<Language>>>,
|
localized_field_ids: HashMap<FieldId, Option<Vec<Language>>>,
|
||||||
@ -32,6 +34,7 @@ impl<'indexer> FacetSearchBuilder<'indexer> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
global_fields_ids_map: GlobalFieldsIdsMap<'indexer>,
|
global_fields_ids_map: GlobalFieldsIdsMap<'indexer>,
|
||||||
localized_attributes_rules: Vec<LocalizedAttributesRule>,
|
localized_attributes_rules: Vec<LocalizedAttributesRule>,
|
||||||
|
filterable_attributes_rules: Vec<FilterableAttributesRule>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let registered_facets = HashMap::new();
|
let registered_facets = HashMap::new();
|
||||||
let normalized_facet_string_docids_sorter = create_sorter(
|
let normalized_facet_string_docids_sorter = create_sorter(
|
||||||
@ -50,6 +53,7 @@ impl<'indexer> FacetSearchBuilder<'indexer> {
|
|||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
global_fields_ids_map,
|
global_fields_ids_map,
|
||||||
localized_attributes_rules,
|
localized_attributes_rules,
|
||||||
|
filterable_attributes_rules,
|
||||||
localized_field_ids: HashMap::new(),
|
localized_field_ids: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,6 +65,13 @@ impl<'indexer> FacetSearchBuilder<'indexer> {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let FacetGroupKey { field_id, level: _level, left_bound } = facet_key;
|
let FacetGroupKey { field_id, level: _level, left_bound } = facet_key;
|
||||||
|
|
||||||
|
let filterable_attributes_features = self.filterable_attributes_features(field_id)?;
|
||||||
|
|
||||||
|
// if facet search is disabled, we don't need to register the facet
|
||||||
|
if !filterable_attributes_features.is_facet_searchable() {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
if deladd == DelAdd::Addition {
|
if deladd == DelAdd::Addition {
|
||||||
self.registered_facets.entry(field_id).and_modify(|count| *count += 1).or_insert(1);
|
self.registered_facets.entry(field_id).and_modify(|count| *count += 1).or_insert(1);
|
||||||
}
|
}
|
||||||
@ -84,6 +95,24 @@ impl<'indexer> FacetSearchBuilder<'indexer> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn filterable_attributes_features(
|
||||||
|
&mut self,
|
||||||
|
field_id: u16,
|
||||||
|
) -> Result<FilterableAttributesFeatures> {
|
||||||
|
let Some(filterable_attributes_features) =
|
||||||
|
self.global_fields_ids_map.metadata(field_id).map(|metadata| {
|
||||||
|
metadata.filterable_attributes_features(&self.filterable_attributes_rules)
|
||||||
|
})
|
||||||
|
else {
|
||||||
|
return Err(InternalError::FieldIdMapMissingEntry(FieldIdMapMissingEntry::FieldId {
|
||||||
|
field_id,
|
||||||
|
process: "facet_search_builder::register_from_key",
|
||||||
|
})
|
||||||
|
.into());
|
||||||
|
};
|
||||||
|
Ok(filterable_attributes_features)
|
||||||
|
}
|
||||||
|
|
||||||
fn locales(&mut self, field_id: FieldId) -> Option<&[Language]> {
|
fn locales(&mut self, field_id: FieldId) -> Option<&[Language]> {
|
||||||
if let Entry::Vacant(e) = self.localized_field_ids.entry(field_id) {
|
if let Entry::Vacant(e) = self.localized_field_ids.entry(field_id) {
|
||||||
let Some(field_name) = self.global_fields_ids_map.name(field_id) else {
|
let Some(field_name) = self.global_fields_ids_map.name(field_id) else {
|
||||||
|
@ -117,9 +117,11 @@ fn compute_facet_search_database(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let rtxn = index.read_txn()?;
|
let rtxn = index.read_txn()?;
|
||||||
let localized_attributes_rules = index.localized_attributes_rules(&rtxn)?;
|
let localized_attributes_rules = index.localized_attributes_rules(&rtxn)?;
|
||||||
|
let filterable_attributes_rules = index.filterable_attributes_rules(&rtxn)?;
|
||||||
let mut facet_search_builder = FacetSearchBuilder::new(
|
let mut facet_search_builder = FacetSearchBuilder::new(
|
||||||
global_fields_ids_map,
|
global_fields_ids_map,
|
||||||
localized_attributes_rules.unwrap_or_default(),
|
localized_attributes_rules.unwrap_or_default(),
|
||||||
|
filterable_attributes_rules,
|
||||||
);
|
);
|
||||||
|
|
||||||
let previous_facet_id_string_docids = index
|
let previous_facet_id_string_docids = index
|
||||||
@ -165,7 +167,13 @@ fn compute_facet_level_database(
|
|||||||
wtxn: &mut RwTxn,
|
wtxn: &mut RwTxn,
|
||||||
mut facet_field_ids_delta: FacetFieldIdsDelta,
|
mut facet_field_ids_delta: FacetFieldIdsDelta,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let facet_leveled_field_ids = index.facet_leveled_field_ids(&*wtxn)?;
|
||||||
for (fid, delta) in facet_field_ids_delta.consume_facet_string_delta() {
|
for (fid, delta) in facet_field_ids_delta.consume_facet_string_delta() {
|
||||||
|
// skip field ids that should not be facet leveled
|
||||||
|
if !facet_leveled_field_ids.contains(&fid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let span = tracing::trace_span!(target: "indexing::facet_field_ids", "string");
|
let span = tracing::trace_span!(target: "indexing::facet_field_ids", "string");
|
||||||
let _entered = span.enter();
|
let _entered = span.enter();
|
||||||
match delta {
|
match delta {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user