Guides / Building Search UI / UI & UX patterns

Introduction

When you create specific landing pages to display search results, it’s handy to be able to redirect users to those dedicated pages, in the situation where the search query matches one of them.

In this tutorial, we’ll see two methods for setting up redirects in an Algolia index: using Rules and using dedicated indices.

Using Rules

The best way to set up redirects is through Rules. You can add add redirect information, as custom data, to any Rule: this data is returned when the Rule is triggered by a search.

Configuring the Rule

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.

In the example below, we want to redirect whenever the query matches “star wars” exactly. If the query is “star wars lightsaber” or “books star wars”, we don’t want to redirect.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$rule = array(
  'objectID' => 'a-rule-id',
  'conditions' => array(array(
    'pattern' => 'star wars',
    'anchoring' => 'is'
  )),
  'consequence' => array(
    'userData' => array(
      'redirect' => 'https://www.google.com/#q=star+wars'
    )
  )
);

$index->saveRule($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 Rules tab.
  3. Select Create your first rule or New rule. In the dropdown, click on the Manual Editor option.
  4. In the Condition(s) section, keep Query toggled on, select Is in the dropdown and enter “star wars” in the input field.
  5. In the Consequence(s) section:
    • Click the Add consequence button and select Return Custom Data.
    • In the input field that appears, add the data to return when the user query matches the Rule: { "redirect": "https://www.google.com/#q=star+wars" }
  6. Don’t forget to save your changes.

Configuring the queryRuleCustomData widget

Now that we have everything set up, we can use the queryRuleCustomData widget to update the page location anytime we find userData containing a redirect.

1
2
3
4
5
6
7
8
9
@Serializable
data class Redirect(val url: String)

val searcher = SearcherSingleIndex(index)
QueryRuleCustomDataConnector<Redirect>(searcher) { redirect ->
    redirect?.url?.let {
        // perform redirect with URL
    }
}

Using a dedicated index

An alternative way to set up redirects is to create a dedicated index with the list of redirects and the query terms that trigger them. This index is separate from your regular index, where your searchable records are. Whenever a user performs a search, you have to look in two indices: the regular one to search for items, and the redirect one that determines whether or not the user should be redirected.

This technique can be useful if you cannot use Rules or if you want access to typo tolerance, synonyms or filters.

Using a dedicated index will force you to trigger two queries: one for the results and one for the redirects. It can have an impact on your search operations usage.

Dataset

1
2
3
4
5
6
7
8
9
10
[
  {
    "url": "https://www.google.com/#q=star+wars",
    "query_terms": ["star wars"]
  },
  {
    "url": "https://www.google.com/#q=star+wars+actors",
    "query_terms": ["george lucas", "luke skywalker"]
  }
]

In this dataset, we give a list of URLs we want to redirect to. For each of them, we define a list of queries that we want to redirect from.

For example, the query “star wars” should redirect to https://www.google.com/#q=star+wars.

You can download the dataset on our GitHub. Have look at how to import it in Algolia here

Configuring the index

We want to redirect only if the query exactly matches one of the query_terms. We’re adding query_terms to our list of attributesForFaceting, so we can filter on it.

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

Creating a custom search client

Now that we have everything set up, we’ll create a custom search client that will send requests to our regular index and to our redirect index in parallel.

The request to the redirect index is sent with:

  • an empty query, so we don’t filter with it
  • a filter on query_terms with the content of the current query, to match only on records that contains the current query exactly
  • hitsPerPage=1, as we only need the first record

Whenever we find hits in this index, we redirect:

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
const client = algoliasearch('YourApplicationID', 'YourSearchOnlyAPIKey');
const redirectIndex = client.initIndex('your_redirect_index_name');

const customSearchClient = {
  async search(requests) {
    const searches = [client.search(requests)];

    if (requests[0].params.query) {
      searches.push(
        redirectIndex.search('', {
          hitsPerPage: 1,
          facetFilters: [`query_terms:${requests[0].params.query}`],
        })
      );
    }

    const [results, redirect] = await Promise.all(searches);

    if (redirect && redirect.hits.length) {
      window.location.href = redirect.hits[0].url;
    }

    return results;
  },
};

const search = instantsearch({
  indexName: 'instant_search',
  searchClient: customSearchClient,
});

Did you find this page helpful?