Optional filters are a powerful tool for influencing the ranking of search results.
Use them to boost or bury records based on specific criteria, but without hiding those records.
For example,
on a website that handles fast food deliveries,
if a user types “hungry” and clicks the “deliver quickly” option,
the website will show the restaurants that can deliver the fastest at the top of the list but still show other restaurants.
You can also use negative optional filters to demote records.
For example, to lower the ranking of restaurants with poor reviews.
Optional filters in rules aren’t available on the Grow plan .
If you signed up for the Community, Essential, or Plus plans before December 15, 2018,
you can only use one optional filter per query.
Update your records
Since optional filters only work with exact matches,
you might need to update your records.
Using the fast food delivery website as an example,
flag restaurants that can deliver within 20 minutes by adding a boolean attribute called can_deliver_quickly
and set it to true
or false
for each record.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[
{
"name" : "Pasta Bolognese" ,
"restaurant" : "Millbrook Deli" ,
"delivery_waiting_time" : 20 ,
"can_deliver_quickly" : true ,
"popularity" : 80
},
{
"name" : "Pasta Bolognese" ,
"restaurant" : "The Hive" ,
"delivery_waiting_time" : 15 ,
"can_deliver_quickly" : true ,
"popularity" : 80
},
{
"name" : "Pasta Bolognese" ,
"restaurant" : "Bert's Inn" ,
"delivery_waiting_time" : 40 ,
"can_deliver_quickly" : false ,
"popularity" : 90
}
]
How to apply optional filters
Set the attribute as an attributeForFaceting
at indexing time.
You can do this either through the API or the Algolia dashboard.
Add the optional filter to your query with the API.
Using the dashboard
Set the attribute to use for faceting in your Algolia dashboard:
Go to the Algolia dashboard and select your Algolia application.
On the left sidebar, select Algolia Search
Search .
Select your Algolia index:
Click the Configuration tab.
Under Filtering and Faceting > Facets
In the Facets subsection of Filtering and Faceting , click Add an attribute and select the optional filter attributes from the list (for example, can_deliver_quickly
).
Save your changes.
You can test filters in the Visual Editor before using them in your code:
Go to the Algolia dashboard and select your Algolia application.
On the left sidebar, select Algolia Search
Search .
Select your Algolia index:
In the sidebar, select Enhance > Rules .
Click New rule and select Visual Editor .
Under Conditions , select Set query condition(s) .
Click Filters .
In the Name field, enter the name of your optional filter (for example, can_deliver_quickly
).
In the Value field, enter true
.
Type something into the Query box, such as *
(to display all matching records)
Click Apply .
Using the example dataset and the query *
`, two out of three records will be displayed.
Using the API
Set the attribute to use for faceting with attributesForFaceting
.
For example:
1
2
3
4
5
6
7
var response = await client . SetSettingsAsync (
"ALGOLIA_INDEX_NAME" ,
new IndexSettings
{
AttributesForFaceting = new List < string > { "can_deliver_quickly" , "restaurant" },
}
);
1
2
3
4
5
6
7
8
9
final response = await client . setSettings (
indexName: "ALGOLIA_INDEX_NAME" ,
indexSettings: IndexSettings (
attributesForFaceting: [
"can_deliver_quickly" ,
"restaurant" ,
],
),
);
1
2
3
4
5
6
7
8
response , err := client . SetSettings ( client . NewApiSetSettingsRequest (
"ALGOLIA_INDEX_NAME" ,
search . NewEmptyIndexSettings () . SetAttributesForFaceting (
[] string { "can_deliver_quickly" , "restaurant" })))
if err != nil {
// handle the eventual error
panic ( err )
}
1
2
3
4
client . setSettings (
"ALGOLIA_INDEX_NAME" ,
new IndexSettings (). setAttributesForFaceting ( Arrays . asList ( "can_deliver_quickly" , "restaurant" ))
);
1
2
3
4
const response = await client . setSettings ({
indexName : ' ALGOLIA_INDEX_NAME ' ,
indexSettings : { attributesForFaceting : [ ' can_deliver_quickly ' , ' restaurant ' ] },
});
1
2
3
4
5
6
var response = client . setSettings (
indexName = "ALGOLIA_INDEX_NAME" ,
indexSettings = IndexSettings (
attributesForFaceting = listOf ( "can_deliver_quickly" , "restaurant" ),
),
)
1
2
3
4
5
6
7
8
9
$response = $client -> setSettings (
'ALGOLIA_INDEX_NAME' ,
[ 'attributesForFaceting' => [
'can_deliver_quickly' ,
'restaurant' ,
],
],
);
1
2
3
4
5
6
7
8
9
response = client . set_settings (
index_name = "ALGOLIA_INDEX_NAME" ,
index_settings = {
"attributesForFaceting" : [
"can_deliver_quickly" ,
"restaurant" ,
],
},
)
1
2
3
4
response = client . set_settings (
"ALGOLIA_INDEX_NAME" ,
Algolia :: Search :: IndexSettings . new ( attributes_for_faceting: [ "can_deliver_quickly" , "restaurant" ])
)
1
2
3
4
5
6
7
8
9
val response = Await . result (
client . setSettings (
indexName = "ALGOLIA_INDEX_NAME" ,
indexSettings = IndexSettings (
attributesForFaceting = Some ( Seq ( "can_deliver_quickly" , "restaurant" ))
)
),
Duration ( 100 , "sec" )
)
1
2
3
4
let response = try await client . setSettings (
indexName : "ALGOLIA_INDEX_NAME" ,
indexSettings : IndexSettings ( attributesForFaceting : [ "can_deliver_quickly" , "restaurant" ])
)
Send the optional filters with your query.
For example:
1
2
3
4
5
6
7
8
9
10
11
var response = await client . SearchSingleIndexAsync < Hit >(
"ALGOLIA_INDEX_NAME" ,
new SearchParams (
new SearchParamsObject
{
OptionalFilters = new OptionalFilters (
new List < OptionalFilters > { new OptionalFilters ( "can_deliver_quickly:true" ) }
),
}
)
);
1
2
3
4
5
6
7
8
final response = await client . searchSingleIndex (
indexName: "ALGOLIA_INDEX_NAME" ,
searchParams: SearchParamsObject (
optionalFilters: [
"can_deliver_quickly:true" ,
],
),
);
1
2
3
4
5
6
7
8
response , err := client . SearchSingleIndex ( client . NewApiSearchSingleIndexRequest (
"ALGOLIA_INDEX_NAME" ) . WithSearchParams ( search . SearchParamsObjectAsSearchParams (
search . NewEmptySearchParamsObject () . SetOptionalFilters ( search . ArrayOfOptionalFiltersAsOptionalFilters (
[] search . OptionalFilters { * search . StringAsOptionalFilters ( "can_deliver_quickly:true" )})))))
if err != nil {
// handle the eventual error
panic ( err )
}
1
2
3
4
5
client . searchSingleIndex (
"ALGOLIA_INDEX_NAME" ,
new SearchParamsObject (). setOptionalFilters ( OptionalFilters . of ( Arrays . asList ( OptionalFilters . of ( "can_deliver_quickly:true" )))),
Hit . class
);
1
2
3
4
const response = await client . searchSingleIndex ({
indexName : ' indexName ' ,
searchParams : { optionalFilters : [ ' can_deliver_quickly:true ' ] },
});
1
2
3
4
5
6
var response = client . searchSingleIndex (
indexName = "ALGOLIA_INDEX_NAME" ,
searchParams = SearchParamsObject (
optionalFilters = OptionalFilters . of ( listOf ( OptionalFilters . of ( "can_deliver_quickly:true" ))),
),
)
1
2
3
4
5
6
7
$response = $client -> searchSingleIndex (
'ALGOLIA_INDEX_NAME' ,
[ 'optionalFilters' => [
'can_deliver_quickly:true' ,
],
],
);
1
2
3
4
5
6
7
8
response = client . search_single_index (
index_name = "ALGOLIA_INDEX_NAME" ,
search_params = {
"optionalFilters" : [
"can_deliver_quickly:true" ,
],
},
)
1
2
3
4
response = client . search_single_index (
"ALGOLIA_INDEX_NAME" ,
Algolia :: Search :: SearchParamsObject . new ( optional_filters: [ "can_deliver_quickly:true" ])
)
1
2
3
4
5
6
7
8
9
10
11
val response = Await . result (
client . searchSingleIndex (
indexName = "ALGOLIA_INDEX_NAME" ,
searchParams = Some (
SearchParamsObject (
optionalFilters = Some ( OptionalFilters ( Seq ( OptionalFilters ( "can_deliver_quickly:true" ))))
)
)
),
Duration ( 100 , "sec" )
)
1
2
3
4
5
6
7
let response : SearchResponse < Hit > = try await client . searchSingleIndex (
indexName : "ALGOLIA_INDEX_NAME" ,
searchParams : SearchSearchParams
. searchSearchParamsObject ( SearchSearchParamsObject ( optionalFilters : SearchOptionalFilters
. arrayOfSearchOptionalFilters ([ SearchOptionalFilters . string ( "can_deliver_quickly:true" )])
))
)
You can also add negative optional filters.
For example, to demote a specific restaurant:
1
2
3
4
5
6
7
8
9
10
11
12
var response = await client . SearchSingleIndexAsync < Hit >(
"ALGOLIA_INDEX_NAME" ,
new SearchParams (
new SearchParamsObject
{
Query = "query" ,
OptionalFilters = new OptionalFilters (
new List < OptionalFilters > { new OptionalFilters ( "restaurant:-Bert's Inn" ) }
),
}
)
);
1
2
3
4
5
6
7
8
9
final response = await client . searchSingleIndex (
indexName: "ALGOLIA_INDEX_NAME" ,
searchParams: SearchParamsObject (
query: "query" ,
optionalFilters: [
"restaurant:-Bert's Inn" ,
],
),
);
1
2
3
4
5
6
7
8
response , err := client . SearchSingleIndex ( client . NewApiSearchSingleIndexRequest (
"ALGOLIA_INDEX_NAME" ) . WithSearchParams ( search . SearchParamsObjectAsSearchParams (
search . NewEmptySearchParamsObject () . SetQuery ( "query" ) . SetOptionalFilters ( search . ArrayOfOptionalFiltersAsOptionalFilters (
[] search . OptionalFilters { * search . StringAsOptionalFilters ( "restaurant:-Bert's Inn" )})))))
if err != nil {
// handle the eventual error
panic ( err )
}
1
2
3
4
5
6
7
client . searchSingleIndex (
"ALGOLIA_INDEX_NAME" ,
new SearchParamsObject ()
. setQuery ( "query" )
. setOptionalFilters ( OptionalFilters . of ( Arrays . asList ( OptionalFilters . of ( "restaurant:-Bert's Inn" )))),
Hit . class
);
1
2
3
4
const response = await client . searchSingleIndex ({
indexName : ' indexName ' ,
searchParams : { query : ' query ' , optionalFilters : [ " restaurant:-Bert's Inn " ] },
});
1
2
3
4
5
6
7
var response = client . searchSingleIndex (
indexName = "ALGOLIA_INDEX_NAME" ,
searchParams = SearchParamsObject (
query = "query" ,
optionalFilters = OptionalFilters . of ( listOf ( OptionalFilters . of ( "restaurant:-Bert's Inn" ))),
),
)
1
2
3
4
5
6
7
8
$response = $client -> searchSingleIndex (
'ALGOLIA_INDEX_NAME' ,
[ 'query' => 'query' ,
'optionalFilters' => [
"restaurant:-Bert's Inn" ,
],
],
);
1
2
3
4
5
6
7
8
9
response = client . search_single_index (
index_name = "ALGOLIA_INDEX_NAME" ,
search_params = {
"query" : "query" ,
"optionalFilters" : [
"restaurant:-Bert's Inn" ,
],
},
)
1
2
3
4
response = client . search_single_index (
"ALGOLIA_INDEX_NAME" ,
Algolia :: Search :: SearchParamsObject . new ( query: "query" , optional_filters: [ "restaurant:-Bert's Inn" ])
)
1
2
3
4
5
6
7
8
9
10
11
12
val response = Await . result (
client . searchSingleIndex (
indexName = "ALGOLIA_INDEX_NAME" ,
searchParams = Some (
SearchParamsObject (
query = Some ( "query" ),
optionalFilters = Some ( OptionalFilters ( Seq ( OptionalFilters ( "restaurant:-Bert's Inn" ))))
)
)
),
Duration ( 100 , "sec" )
)
1
2
3
4
5
6
7
8
let response : SearchResponse < Hit > = try await client . searchSingleIndex (
indexName : "ALGOLIA_INDEX_NAME" ,
searchParams : SearchSearchParams . searchSearchParamsObject ( SearchSearchParamsObject (
query : "query" ,
optionalFilters : SearchOptionalFilters
. arrayOfSearchOptionalFilters ([ SearchOptionalFilters . string ( "restaurant:-Bert's Inn" )])
))
)
Optional or facet filters
Whether to use optional filters or facet filters
depends on your goals:
Use optional filters to boost records.
Use facet filters if you need to filter out records.
Optional filters, replicas and sorting
If you’re using a sort-by attribute
with standard replicas, you can’t use optional filters to boost or bury records.
The sort-by attribute always takes precedence.
Optional filters are incompatible with virtual replicas and relevant sorting .
Trying to use optional filters with virtual replicas leads to unexpected behavior.
Further reading