mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-03-06 22:02:34 +08:00
Add a test on filterable attributes rules priority
**Changes:** - Add a new test playing with filterable attributes rules priority - Optimize the faceted field selector avoiding to match false positives
This commit is contained in:
parent
a7a62e5e4c
commit
5fa4b5c50a
@ -623,3 +623,136 @@ async fn search_with_pattern_filter_settings_scenario_1() {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_filterable_attributes_priority() {
|
||||||
|
// Test that the filterable attributes priority is respected
|
||||||
|
|
||||||
|
// check if doggos.name is filterable
|
||||||
|
test_settings_documents_indexing_swapping_and_search(
|
||||||
|
&NESTED_DOCUMENTS,
|
||||||
|
&json!({"filterableAttributes": [
|
||||||
|
// deactivated filter
|
||||||
|
{"patterns": ["doggos.a*"], "features": {"facetSearch": false, "filter": {"equality": false, "comparison": false}}},
|
||||||
|
// activated filter
|
||||||
|
{"patterns": ["doggos.*"]},
|
||||||
|
]}),
|
||||||
|
&json!({
|
||||||
|
"filter": "doggos.name = bobby"
|
||||||
|
}),
|
||||||
|
|response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 852,
|
||||||
|
"father": "jean",
|
||||||
|
"mother": "michelle",
|
||||||
|
"doggos": [
|
||||||
|
{
|
||||||
|
"name": "bobby",
|
||||||
|
"age": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "buddy",
|
||||||
|
"age": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cattos": "pésti"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// check if doggos.name is filterable 2
|
||||||
|
test_settings_documents_indexing_swapping_and_search(
|
||||||
|
&NESTED_DOCUMENTS,
|
||||||
|
&json!({"filterableAttributes": [
|
||||||
|
// deactivated filter
|
||||||
|
{"patterns": ["doggos"], "features": {"facetSearch": false, "filter": {"equality": false, "comparison": false}}},
|
||||||
|
// activated filter
|
||||||
|
{"patterns": ["doggos.*"]},
|
||||||
|
]}),
|
||||||
|
&json!({
|
||||||
|
"filter": "doggos.name = bobby"
|
||||||
|
}),
|
||||||
|
|response, code| {
|
||||||
|
snapshot!(code, @"200 OK");
|
||||||
|
snapshot!(json_string!(response["hits"]), @r###"
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 852,
|
||||||
|
"father": "jean",
|
||||||
|
"mother": "michelle",
|
||||||
|
"doggos": [
|
||||||
|
{
|
||||||
|
"name": "bobby",
|
||||||
|
"age": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "buddy",
|
||||||
|
"age": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cattos": "pésti"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// check if doggos.age is not filterable
|
||||||
|
test_settings_documents_indexing_swapping_and_search(
|
||||||
|
&NESTED_DOCUMENTS,
|
||||||
|
&json!({"filterableAttributes": [
|
||||||
|
// deactivated filter
|
||||||
|
{"patterns": ["doggos.a*"], "features": {"facetSearch": false, "filter": {"equality": false, "comparison": false}}},
|
||||||
|
// activated filter
|
||||||
|
{"patterns": ["doggos.*"]},
|
||||||
|
]}),
|
||||||
|
&json!({
|
||||||
|
"filter": "doggos.age > 2"
|
||||||
|
}),
|
||||||
|
|response, code| {
|
||||||
|
snapshot!(code, @"400 Bad Request");
|
||||||
|
snapshot!(json_string!(response), @r###"
|
||||||
|
{
|
||||||
|
"message": "Index `test`: Attribute `doggos.age` is not filterable. Available filterable attributes are: `doggos.age`, `doggos.name`.\n1:11 doggos.age > 2",
|
||||||
|
"code": "invalid_search_filter",
|
||||||
|
"type": "invalid_request",
|
||||||
|
"link": "https://docs.meilisearch.com/errors#invalid_search_filter"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// check if doggos is not filterable
|
||||||
|
test_settings_documents_indexing_swapping_and_search(
|
||||||
|
&NESTED_DOCUMENTS,
|
||||||
|
&json!({"filterableAttributes": [
|
||||||
|
// deactivated filter
|
||||||
|
{"patterns": ["doggos"], "features": {"facetSearch": false, "filter": {"equality": false, "comparison": false}}},
|
||||||
|
// activated filter
|
||||||
|
{"patterns": ["doggos.*"]},
|
||||||
|
]}),
|
||||||
|
&json!({
|
||||||
|
"filter": "doggos EXISTS"
|
||||||
|
}),
|
||||||
|
|response, code| {
|
||||||
|
snapshot!(code, @"400 Bad Request");
|
||||||
|
snapshot!(json_string!(response), @r###"
|
||||||
|
{
|
||||||
|
"message": "Index `test`: Attribute `doggos` is not filterable. Available filterable attributes are: `doggos.age`, `doggos.name`.\n1:7 doggos EXISTS",
|
||||||
|
"code": "invalid_search_filter",
|
||||||
|
"type": "invalid_request",
|
||||||
|
"link": "https://docs.meilisearch.com/errors#invalid_search_filter"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
@ -342,16 +342,31 @@ fn match_pattern_by_features(
|
|||||||
filter: &impl Fn(&FilterableAttributesFeatures) -> bool,
|
filter: &impl Fn(&FilterableAttributesFeatures) -> bool,
|
||||||
) -> PatternMatch {
|
) -> PatternMatch {
|
||||||
let mut selection = PatternMatch::NoMatch;
|
let mut selection = PatternMatch::NoMatch;
|
||||||
|
|
||||||
|
// `can_match` becomes false if the field name matches (PatternMatch::Match) any pattern that is not facet searchable or filterable,
|
||||||
|
// this ensures that the field doesn't match a pattern with a lower priority, however it can still match a pattern for a nested field as a parent (PatternMatch::Parent).
|
||||||
|
// See the test `search::filters::test_filterable_attributes_priority` for more details.
|
||||||
|
let mut can_match = true;
|
||||||
|
|
||||||
// Check if the field name matches any pattern that is facet searchable or filterable
|
// Check if the field name matches any pattern that is facet searchable or filterable
|
||||||
for pattern in filterable_attributes {
|
for pattern in filterable_attributes {
|
||||||
|
match pattern.match_str(field_name) {
|
||||||
|
PatternMatch::Match => {
|
||||||
|
let features = pattern.features();
|
||||||
|
if filter(&features) && can_match {
|
||||||
|
return PatternMatch::Match;
|
||||||
|
} else {
|
||||||
|
can_match = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatternMatch::Parent => {
|
||||||
let features = pattern.features();
|
let features = pattern.features();
|
||||||
if filter(&features) {
|
if filter(&features) {
|
||||||
match pattern.match_str(field_name) {
|
selection = PatternMatch::Parent;
|
||||||
PatternMatch::Match => return PatternMatch::Match,
|
|
||||||
PatternMatch::Parent => selection = PatternMatch::Parent,
|
|
||||||
PatternMatch::NoMatch => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PatternMatch::NoMatch => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selection
|
selection
|
||||||
|
Loading…
x
Reference in New Issue
Block a user