mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-06-06 20:25:40 +00:00
Attributes to search on supports nested wildcards
This commit is contained in:
parent
71ab11f1fe
commit
8bd8e744f3
@ -120,17 +120,39 @@ impl<'ctx> SearchContext<'ctx> {
|
|||||||
let searchable_fields_weights = self.index.searchable_fields_and_weights(self.txn)?;
|
let searchable_fields_weights = self.index.searchable_fields_and_weights(self.txn)?;
|
||||||
let exact_attributes_ids = self.index.exact_attributes_ids(self.txn)?;
|
let exact_attributes_ids = self.index.exact_attributes_ids(self.txn)?;
|
||||||
|
|
||||||
let mut wildcard = false;
|
let mut universal_wildcard = false;
|
||||||
|
|
||||||
let mut restricted_fids = RestrictedFids::default();
|
let mut restricted_fids = RestrictedFids::default();
|
||||||
for field_name in attributes_to_search_on {
|
for field_name in attributes_to_search_on {
|
||||||
if field_name == "*" {
|
if field_name == "*" {
|
||||||
wildcard = true;
|
universal_wildcard = true;
|
||||||
// we cannot early exit as we want to returns error in case of unknown fields
|
// we cannot early exit as we want to returns error in case of unknown fields
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let searchable_weight =
|
let searchable_weight =
|
||||||
searchable_fields_weights.iter().find(|(name, _, _)| name == field_name);
|
searchable_fields_weights.iter().find(|(name, _, _)| name == field_name);
|
||||||
|
|
||||||
|
// The field is not searchable but may contain a wildcard pattern
|
||||||
|
if searchable_weight.is_none() && field_name.contains("*") {
|
||||||
|
let matching_searchable_weights: Vec<_> = searchable_fields_weights
|
||||||
|
.iter()
|
||||||
|
.filter(|(name, _, _)| {
|
||||||
|
Self::matches_wildcard_pattern(field_name, name)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !matching_searchable_weights.is_empty() {
|
||||||
|
for (_name, fid, weight) in matching_searchable_weights {
|
||||||
|
if exact_attributes_ids.contains(fid) {
|
||||||
|
restricted_fids.exact.push((*fid, *weight));
|
||||||
|
} else {
|
||||||
|
restricted_fids.tolerant.push((*fid, *weight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (fid, weight) = match searchable_weight {
|
let (fid, weight) = match searchable_weight {
|
||||||
// The Field id exist and the field is searchable
|
// The Field id exist and the field is searchable
|
||||||
Some((_name, fid, weight)) => (*fid, *weight),
|
Some((_name, fid, weight)) => (*fid, *weight),
|
||||||
@ -160,7 +182,7 @@ impl<'ctx> SearchContext<'ctx> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if wildcard {
|
if universal_wildcard {
|
||||||
self.restricted_fids = None;
|
self.restricted_fids = None;
|
||||||
} else {
|
} else {
|
||||||
self.restricted_fids = Some(restricted_fids);
|
self.restricted_fids = Some(restricted_fids);
|
||||||
@ -168,6 +190,34 @@ impl<'ctx> SearchContext<'ctx> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn matches_wildcard_pattern(wildcard_pattern: &str, name: &str) -> bool {
|
||||||
|
let wildcard_subfields: Vec<&str> = wildcard_pattern.split(".").collect();
|
||||||
|
let name_subfields: Vec<&str> = name.split(".").collect();
|
||||||
|
|
||||||
|
// Deep wildcard matches all attributes after ('**')
|
||||||
|
if !wildcard_subfields.is_empty() && wildcard_subfields.last() == Some(&"**") {
|
||||||
|
let prefix_len = wildcard_subfields.len() - 1;
|
||||||
|
if prefix_len > name_subfields.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wildcard_subfields[..prefix_len]
|
||||||
|
.iter()
|
||||||
|
.zip(name_subfields.iter())
|
||||||
|
.all(|(wc, sf)| *wc == "*" || *wc == *sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using single wildcard ('*') should match length (e.g. 'a.*.c' matches 'a.b.c')
|
||||||
|
// where '*' can match any single segment
|
||||||
|
if wildcard_subfields.len() != name_subfields.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wildcard_subfields.iter()
|
||||||
|
.zip(name_subfields.iter())
|
||||||
|
.all(|(wc, sf)| *wc == "*" || *wc == *sf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user