Adding search parameters dynamically
Rules are a powerful tool that let you take decisions for the user and improve their experience based on what they search for. When combined with query time settings, you can leverage Rules to make your search smarter.
Imagine you’re developing an app to search for airports. Algolia lets you use geolocation functionality to rank results based how far or distant an item is from a given point. The problem with this approach is that, depending on your search, the closest airport might not be the most relevant result. For example, let’s say a user is in Paris. With a geo-located search experience, the first result they may get is Le Bourget, a small airport near the center of the city that services private jets and air shows. This is an unlikely choice for a top result. Most users will be looking for Roissy CDG or Orly.
Distance-based ranking is convenient when you’re looking for airports based on your location. Yet, as soon as you start looking for specific cities or countries, distance-based ranking doesn’t necessarily work anymore. What we want is to keep geo-located results, but disable it as soon as we search for a specific city or country. In that case, we want to fall back on some other metric, like the number of liaisons. Because many Algolia settings, like aroundLatLngViaIP
, are available at query time, you can use Rules to detect a search for a specific city or country and change search parameters on the fly.
Dataset Example
Back to the airports example. Imagine we have the following dataset:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
[
{
"name": "Orly",
"city": "Paris",
"country": "France",
"_geoloc": { "lat": 48.725278, "lng": 2.359444 },
"nb_airline_liaisons": 404
},
{
"name": "Charles De Gaulle",
"city": "Paris",
"country": "France",
"_geoloc": { "lat": 49.012779, "lng": 2.55 },
"nb_airline_liaisons": 1041
},
{
"name": "Le Bourget",
"city": "Paris",
"country": "France",
"_geoloc": { "lat": 48.961487, "lng": 2.436966 },
"nb_airline_liaisons": 0
},
{
"name": "Ben Gurion",
"city": "Tel-Aviv",
"country": "Israel",
"_geoloc": { "lat": 32.011389, "lng": 34.886667 },
"nb_airline_liaisons": 271
},
{
"name": "Haifa",
"city": "Haifa",
"country": "Israel",
"_geoloc": { "lat": 32.809444, "lng": 35.043056 },
"nb_airline_liaisons": 4
},
{
"name": "Pudong",
"city": "Shanghai",
"country": "China",
"_geoloc": { "lat": 31.143378, "lng": 121.805214 },
"nb_airline_liaisons": 825
},
{
"name": "Hongqiao Intl",
"city": "Shanghai",
"country": "China",
"_geoloc": { "lat": 31.197875, "lng": 121.336319 },
"nb_airline_liaisons": 411
}
]
The first thing we could do is use nb_airline_liaisons
for custom ranking, so we prioritize airports with many liaisons. Yet, as soon as we set aroundLatLngViaIP
to true
in our search code, this custom ranking would be overridden in favor of geographical proximity, which is part of ranking formula.
For example, we would still have the Paris problem because Le Bourget, even if it has the lowest number of liaisons, has the closest geo proximity to the user.
Other examples: if a user is in Paris and searches for “israel”, they would first get Haifa airport, because this is the Israeli airport that’s the closest to Paris. Yet, it wouldn’t make sense, as Haifa airport is relatively small. “Ben Gurion” is a better choice. Same goes if they were looking for “shanghai”. Hongqiao airport is geographically closer to Paris, but not as big as Pudong airport, which is only 30 km away from Hongqiao.
We can fix this by setting a Rule that detects searches for a specific city or country and disables aroundLatLngViaIP
as a consequence. Whenever a user specifically looks for a city or country name, like “paris”, “israel”, or “shanghai”, the distance-based search would be disabled, falling back on custom ranking by number of liaisons.
Using the API
To achieve this, you first need to use nb_airline_liaisons
for custom ranking. You also need to set city
and country
as attributes for faceting, so we can detect whenever a query matches any of them.
1
2
3
4
5
6
7
$index->setSettings([
'customRanking' => [
'desc(nb_airline_liaisons)'
],
'attributesForFaceting' => [
'city', 'country'
]);
Then, you can set a Rule that detects matches in facets city
and country
, and changes the search parameters accordingly. For this, you need to use the batchRules
method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$index->saveRules([
[
'objectID' => 'country',
'conditions' => array(array(
'pattern' => '{facet:country}',
'anchoring' => 'contains'
)),
'consequence' => [
'params' => [
'aroundLatLngViaIP' => false
]
]
],
[
'objectID' => 'city',
'conditions' => array(array(
'pattern' => '{facet:city}',
'anchoring' => 'contains'
)),
'consequence' => [
'params' => [
'aroundLatLngViaIP' => false
]
]
]
]);
Using the Dashboard
You can also add your Rules in your Algolia dashboard.
Custom ranking
- Select the Search product icon on your dashboard and then select your index.
- Click on the Configuration tab.
- In the Ranking and Sorting section, click the “Add a Custom Ranking” button and select the
nb_airline_liaisons
attribute from the dropdown. - In the Facets subsection of Filtering and Faceting, click the “Add an attribute” button and select the
country
andcity
attributes from the dropdown. - Save your changes.
Rules
- Select the Rules section from the left sidebar menu in the Algolia dashboard.
- Under the heading Rules, select the index you are adding a Rule to.
- Select Create your first rule or New rule. In the dropdown, click on the Manual Editor option.
- In the Condition(s) section, keep Query toggled on, select Contains in the dropdown, and select the option Add Facet “country” from the input dropdown.
{facet:country}
should then be displayed in the input. - In the Consequence(s) section:
- Click the Add consequence button and select Add Query Parameter.
- In the input field that appears, add the JSON parameters you want to apply when the user’s query matches the Rule:
{ "aroundLatLngViaIP": false }
- Don’t forget to save your changes.
- Click the New Rule button again and then Manual Editor.
- In the Condition(s) section, keep Query toggled on, select Contains in the dropdown, and select the option Add Facet “city” from the input dropdown.
{facet:city}
should then be displayed in the input. - In the Consequence(s) section:
- Click the Add consequence button again and select Add Query Parameter.
- In the input field that appears, add the JSON parameters you want to apply when the user’s query matches the Rule:
{ "aroundLatLngViaIP": false }
- Don’t forget to save your changes.
Query time
Once your Rule is ready, you can search for airports, cities, and countries. When the query exactly matches a city or a country from your dataset, the Rule sets aroundLatLngViaIP
to false
regardless of the parameters you set in the query.
Therefore, when a user searches for “paris” or “china”, matching airports are ranked by nb_airline_liaisons
. When not searching for either a city or a country, airports are ranked by distance to the user’s current location.
1
2
3
$results = $index->search('query', [
'aroundLatLngViaIP' => true
]);