Adding Search Parameters Dynamically

Query 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 Query 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 query 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',
    'condition' => [
      'pattern' => '{facet:country}',
      'anchoring' => 'contains'
    ],
    'consequence' => [
      'params' => [
        'aroundLatLngViaIP' => false
      ]
    ]
  ],
  [
    'objectID' => 'city',
    'condition' => [
      'pattern' => '{facet:city}',
      'anchoring' => 'contains'
    ],
    'consequence' => [
      'params' => [
        'aroundLatLngViaIP' => false
      ]
    ]
  ]
]);

Using the Dashboard

You can also add your rules in your Algolia dashboard.

Custom ranking

  1. Go to your dashboard and select your target index.
  2. Click on the Configuration tab.
  3. In the Ranking and Sorting section, click the “Add a Custom Ranking” button and select the nb_airline_liaisons attribute from the dropdown.
  4. In the Facets subsection of Filtering and Faceting, click the “Add an attribute” button and select the country and city attributes from the dropdown.
  5. Save your changes.

Query Rules

  1. Go to the Query Rules tab.
  2. Click the “New rule” button.
  3. In the Condition section:
    • Set the anchoring of “if the query…” to Contains.
    • Type {facet:country} in the input field and press enter.
  4. In the Consequences section:
    • Click the “Add consequence” button and select Add Query Parameter.
    • In the Custom JSON Data panel that shows up, add the data you want to return when your user’s query matches the rule: { "aroundLatLngViaIP": false }
  5. Click Save.
  6. Click the “New rule” button again.
  7. In the Condition section:
    • Set the anchoring of “if the query…” to Contains.
    • Type {facet:city} in the input field and press enter.
  8. In the Consequences section:
    • Click the “Add consequence” button and select Add Query Parameter.
    • In the Custom JSON Data panel that shows up, add the data you want to return when your user’s query matches the rule: { "aroundLatLngViaIP": false }
  9. Click Save.

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
]);

Did you find this page helpful?