Sorting

Introduction

When a user searches in your website/app, you want to make sure he/she will find the most relevant results. And to configure the best relevance, there are two things that should be taken into account:

  • The textual relevance: calculates how well the query matches the searchable words of a record
  • the business relevance: takes into account your business metrics: number of sales/views/likes, featured objects, price, date…

Algolia completely re-invented how search engines handle the ranking of the results. And made a lot of big improvements, among which:

  • Merging the textual and the business relevance is much easier
  • You can make sure that the business relevance won’t override the textual relevance
  • The ranking formula is easy to maintain, more stable, and is relevant for the whole catalog, not only for the most popular queries

Pretty neat, huh? So let’s see how it works!

The Tie-Breaking algorithm

Our ranking formula is based on a tie-breaking algorithm. We wrote a guide on relevance explaining this algorithm if you want to understand it fully. For now, let’s explain the main ideas:

  • The ranking Formula is based on a list of rules that apply one after the other
  • The higher a rule is one the list, the more impact it will have on the ranking
  • The first rules of the formula are related to the textual relevance, and the last one (custom) contains the business metrics that you configured in the setting called customRanking.

Configure the sorting strategy

Let’s take for example an index containing records sortable by number of views, or by price:

{
  "name": "object name",
  "number_of_views": 142,
  "price": 41.99,
  // ...
}

The attributes used for the sorting must be formatted as a numerical value or a boolean, not as a string. For booleans we’ll consider true=1 and false=0.

There are multiple ways to configure the sort. Let’s go through them:

Sort by Relevance using the Custom Ranking

That’s the most common way to configure a sorting strategy. Your metric will be used in the custom rule of the Ranking Formula, and intelligently merged with the textual relevance to provide the most relevant results.

To sort your results by number_of_views, you can go to the setting customRanking at the top of the Ranking tab of your dashboard.

Sorting 1

Sort by number of views using the Custom Ranking setting

You can set the sort to ascending (smaller values are considered better) or descending (bigger values are considered better) by clicking on the Asc/ Desc button.

Sort by an attribute

In most cases it’s recommended to use the Custom Ranking, but in some situations you want to make a sorting strategy that will override the textual relevance. For example when you sort by ascending price: a cheaper item should always be ranked higher, even if its textual relevance is worse.

When your sort should take precedence over the other ranking rules, you can set it at the top of the Ranking Formula (at the bottom of the Ranking tab of your dashboard).

The default rules of the Ranking Formula are designed to work nicely in the vast majority of use-cases. You can add a rule on top to make a hard-sorting by price or date, but you probably shouldn’t remove the default rules.

By setting a sorting attribute at the top of the Ranking Formula, you override strongly the textual relevance elements of the Ranking Formula. To avoid having results with a poor textual relevance, we recommend setting typoTolerance="min".

Complex sorting strategy using multiple metrics

The ranking formula is completely customizable, which means the possibilities are endless and you can virtually build every sorting strategy you would want to use.

Regarding the possibility of sorting by a non-numeric attributes, by alphabetical order for instance, it is possible to do so by adding a new attribute as a new custom ranking criteria, choosing the order you want it sorted and by finally moving this custom ranking criteria at the top of your ranking formula. However, this would automatically disable all the other ranking criteria, and will impact the textual relevance of your search - which is obviously not recommended.

If you want to build a more complex ranking strategy, for example by using multiple sorting metrics, we’d recommend reading our guide about Relevance explaining in detail the inner-workings of the Ranking Formula.

Multiple sorting Strategies

You may also want to display multiple sorting options to your users, for example ascending sort on price, descending sort on price, popularity, …

To achieve the best performance possible, we pre-compute your sort criteria at indexing-time. This is an optimization (and one of the main differences we have with other engines) to ensure you will always have outstanding performance at query-time. The consequence of this approach is that your sort criteria are statically defined in the index: each index has a unique sorting strategy.

If you want to have two different sorts, you will need to duplicate your data in two indices. In order to avoid sending your data twice, you can use the primary-replicat feature: it allows you to automatically replicate the content of one index (called “primary”) in other indices (called “replicas”) that can have different settings (in our case different sort criteria). You only need to push the data to the “primary” index, and we’ll synchronize the replicas automatically.

Sorting 2

Creating two replica indices

To create replica indices, you need to list their name in the primary index settings in the dashboard. Or you can use the API:

index.set_settings :replicas => ['products_by_price_asc', 'products_by_price_desc']
class products < ActiveRecord::Base
  attr_protected
  include AlgoliaSearch
  algoliasearch per_environment: true do
    searchableAttributes [:name, :author, :editor]
    customRanking ['asc(name)']
    # define a replica index to sort by `price` ASC
    add_replica 'products_by_price_asc', per_environment: true do
      searchableAttributes [:name, :author, :editor]
      customRanking ['asc(price)']
    end
    # define a replica index to sort by `price` DESC
    add_replica 'products_by_price_desc', per_environment: true do
      searchableAttributes [:name, :author, :editor]
      customRanking ['desc(price)']
    end
  end
end
index.set_settings({"replicas": ["products_by_price_asc", "products_by_price_desc"]})
index.setSettings({
  replicas: ["products_by_price_asc", "products_by_price_desc"]
})
<?php
$index->setSettings(array(
  "replicas" => array("products_by_price_asc", "products_by_price_desc")
));
<?php
/**
 *
 * @ORMEntity
 *
 * @AlgoliaIndex(
 *     replicas = {"products_by_price_asc", "products_by_price_desc"}
 * )
 *
 */
class products
{
}
index.setSettings(
	new IndexSettings()
		.setReplicas(Arrays.asList("products_by_price_asc", "products_by_price_desc"))
	);
settings := make(map[string]interface{})
settings["replicas"] = []string{"products_by_price_asc", "products_by_price_desc"}
index.SetSettings(settings)
curl --header 'X-Algolia-API-Key: YourAPIKey' \
     --header 'X-Algolia-Application-Id: YourApplicationID' \
     --data-binary '{"replicas": ["products_by_price_asc", "products_by_price_desc"]}' \
     --request PUT https://APP_ID.algolia.net/1/indexes/YourIndexName/settings
index.SetSettings(JObject.Parse(@"{""replicas"":[""products_by_price_asc"", ""products_by_price_desc""]}"));
val result: Future[Task] = client.execute {
  changeSettings of "myIndex" `with` IndexSettings(
  	replicas = Some(Seq("products_by_price_asc", "products_by_price_desc"))
  )
}

Now that you have multiple indices, you can configure a different sorting strategy on each. And you’ll only need to change the index you’re targeting to change the sorting of the results.