Adding Filters Based on the Query

Sometimes, specific terms can act as cues that you can use to filter down the hits that your users get.

For example, imagine you have a website where people can search for dishes from restaurants with home-delivery service. If someone types “gluten-free”, you could use this to filter out any dish that has “gluten” in its list of allergens.

To do this, you can leverage Algolia’s Query Rules and trigger custom filters based on what users search for.

Positive Filters

Imagine you want to allow users who search for dishes to automatically filter out every non-diet-friendly dish whenever their search query contains the term “diet”. A good approach would be to leverage the special attribute _tags and use it to categorize dishes depending on their individual qualities:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
  {
    "name": "Chicken Stuffed Baked Avocados",
    "restaurant": "The Hive",
    "_tags": ["low-carb"]
  },
  {
    "name": "Spinach Quiche",
    "restaurant": "Bert's Inn",
    "_tags": ["low-carb", "vegetarian"]
  },
  {
    "name": "Pizza Chicken Bake",
    "restaurant": "Millbrook Deli",
    "_tags": ["cheese"]
  },
  {
    "name": "Strawberry Sorbet",
    "restaurant": "The Hive",
    "_tags": ["low-fat", "vegetarian", "vegan"]
  }
]

When users add “diet” in their search, you want to automatically bring in every record that has “low-carb” or “low-fat” in their _tags attribute. Because _tags comes ready and optimized for filtering, you don’t have to set it as an attribute for faceting. You can directly create a new rule that detects the term “diet” in a query, and applies a positive filter on tags “low-carb” and “low-fat”.

Note that you also need to add a consequence in your rule to remove the word “diet” from your query. This way, it won’t be used as a search term, only for filtering purposes.

Using the API

To add a rule, you need to use the saveRule method. When setting a rule, you need to define a condition and a consequence.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$rule = [
  'objectID' => 'diet-rule',
  'condition' => [
    'pattern'   => 'diet',
    'anchoring' => 'contains',
  ],
  'consequence' => [
    'params' => [
      'filters' => '"low-carb" OR "low-fat"',
      'query' => [
        'edits' => [
          [
            'type' => 'remove',
            'delete' => 'diet'
          ]
        ]
      ]
    ]
  ]
];

$response = $index->saveRule($rule);

Using the Dashboard

You can also add your rules in your Algolia dashboard.

  • Go to your dashboard and select your index.
  • Click the Query Rules tab.
  • Click the New rule button.
  • In the Condition section:
    • In the If the query… input field, set the anchoring to Contains.
    • Type “diet” in the input field and press Enter.
  • 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 to return when the user query matches the rule: { "filters": "'low-carb' OR 'low-fat'" }
    • Click the Add consequence button and select Remove Word.
    • Type “diet” in the input field and press Enter.
  • Click Save.

Negative Filters

Imagine you want to allow users who search for dishes to automatically filter out every non-gluten-free dish whenever their search query contains the term “gluten-free”.

You could add “Gluten-free” in the title (e.g., “Gluten-free Pasta Dough”) but this would force you to do it for every dish that doesn’t contain gluten, even those that don’t typically do (e.g., “Leek Soup” or “Fruit Salad”). When a user is looking for “gluten-free” dishes, it’s safer to assume they want everything that matches their search and doesn’t have gluten, not that they’re looking for dishes with the words “Gluten-free” in the title.

You could maintain a list of tags (with the special _tags attribute), but you may want to keep allergens separate, especially if you don’t want to make them searchable.

Instead, a better approach is to create a more explicit list with all allergens:

1
2
3
4
5
6
7
8
9
10
11
12
[
  {
    "name": "Pasta Bolognese",
    "restaurant": "Millbrook Deli",
    "allergens": ["eggs", "lactose"]
  },
  {
    "name": "Breakfast Waffles",
    "restaurant": "The Hive",
    "allergens": ["gluten", "lactose"]
  }
]

When users add “gluten-free” in their search, you want to automatically filter out every record that has “gluten” in their allergens attribute. To do so, you first need to set allergens in your list of attributes for faceting. Then, you can create a new rule that filters out unwanted records based on the allergens facet values.

Using the API

First, you need to set allergens as attributesForFaceting. This happens at indexing time.

1
2
3
4
5
$index->setSettings([
  'attributesForFaceting' => [
    "allergens"
  ]
]);

Then, you can set a query rule that detects the term “gluten-free” in a query, and applies a negative filter on facet value allergens:gluten. For this, you need to use the saveRule method.

Note that you also need to add a consequence in your rule to remove the word “gluten-free” from your query. This way, it won’t be used as a search term, only for filtering purposes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$rule = [
  'objectID' => 'gluten-free-rule',
  'condition' => [
    'pattern'   => 'gluten-free',
    'anchoring' => 'contains',
  ],
  'consequence' => [
    'params' => [
      'filters' => 'NOT allergens:gluten',
      'query' => [
        'edits' => [
          'type' => 'remove',
          'delete' => 'gluten-free'
        ]
      ]
    ]
  ]
];

$response = $index->saveRule($rule['objectID'], $rule);

Using the Dashboard

You can also add your rules in your Algolia dashboard.

  1. Go to your dashboard and select your index.
  2. Click the Configuration tab.
  3. In the Facets subsection of Filtering and Faceting, click the “Add an attribute” button and select the allergens attribute from the dropdown.
  4. Click the Query Rules tab.
  5. Click the “New rule” button.
  6. In the Condition section:
    • Set the anchoring of “if the query…” to Contains.
    • Type “gluten-free” in the input field and press Enter.
  7. 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 the user query matches the rule: { "filters": "NOT allergens:gluten" }
    • Click the “Add consequence” button again and select Remove Word.
    • Type gluten-free in the input field and press enter.
  8. Click Save.

Numerical filtering

Use Case

Imagine the query “cheap toaster 800w”. Query Rules can be used to filter the results by “toaster” and “prices between 0 and 25”, so that the only textual search is the remaining term, “800w”, which could further be used to limit the results with that wattage.

Rule

If query = “cheap toaster” then price < 10 and type=toaster

Note: This requires 2 rules.

API

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
// turn json into an array
$rules = array(
  array(
    'objectID' => 'toaster',
    'condition' => array(
      'pattern' => 'toaster',
      'anchoring' => 'contains'
    ),
    'consequence' => array(
      'params' => array(
        'query' => array(
          'remove' => 'toaster'
        ),
        'filters' => 'product_type:toaster'
      )
    )
  ),
  array(
    'objectID' => 'cheap',
    'condition' => array(
      'pattern' => 'cheap',
      'anchoring' => 'contains'
    ),
    'consequence' => array(
      'params' => array(
        'query' => array(
          'remove' => 'cheap'
        ),
        'filters' => 'price < 10'
      )
    )
  )
);

// push rule to index
$index->batchRules($rules);

Dashboard

Since there are two rules, you’ll need to set up both separately.

Preparation:

  1. Go to your dashboard and select your target index.
  2. Click the Configuration tab.
  3. In the Facets subsection of Filtering and Faceting, click the “Add an attribute” button and select the product_type attribute from the dropdown.

For the first rule:

  1. Click 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 toaster 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: { "filters": "product_type:toaster" }
    • Click the Add consequence button again and select Remove Word.
    • Type toaster in the input field and press enter.
  5. Click Save.

For the second rule:

  1. Go back 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 cheap 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: { "filters": "price<10" }
    • Click the Add consequence button and select Remove Word.
    • Type “cheap” in the input field and press Enter.
  5. Click Save.

Did you find this page helpful?