Guides / Managing results / Refine results

Facets let you create categories on a select group of attributes, so your end users can refine their search. For example, on an index of books, useful facets might be author and genre. Additionally, Algolia calculates how many results there are for each facet. It allows you to display facets and facet counts on the UI for the user to filter down results (e.g., by author or genre).

Faceting is a common search feature that Algolia provides out of the box. To leverage faceting, you need to enable it on a per-attribute basis with the attributesForFaceting parameter. It allows you to:

  • List all the possible values for the selected attributes and return contextual values and counts with each search result.
  • Compute a facet count or the number of records matching each value of the attribute.
  • Enable search within the values of this attribute (known as search for facet values).

What is a facet?

Faceted search is a way of classifying records, allowing users to narrow down results. Facets correspond to those taxonomies, which let users refine results by multiple dimensions at a time.

For a book index, facets can be author or genre. For a luxury shop, they can be brands or designers. You can think of facets as filterable categories. In the context of Algolia, we derive these facets from attributes.

Difference between filtering and faceting

Filtering and faceting often get mixed up because there’s much overlap between them, but understanding the difference is essential. In general, both help to restrict a search to a subset of results. There are cases where the end-user doesn’t see these restrictions at all, for example, when automatically filtering to the records they’re allowed to see based on their user ID. In contrast, faceting is useful when building a UI, where users can select facets categories to refine their search further.

Practically speaking, you always use filtering to narrow down search results. Faceting is a subset filtering: it goes further by providing users with a list of all the values features, counts, and search for facet values. They can narrow down results by several complex dimensions at a time.

Declaring attributes for faceting

To make an attribute filterable or facetable, you need to add the attribute to your attributesForFaceting list. You can do this either in the dashboard or through the API.

For example, if you wanted to make your genre and author attributes available for both faceting and filtering, you’d need to apply the following setting:

1
2
3
4
5
6
$index->setSettings([
  'attributesForFaceting' => [
    "genre",
    "author"
  ]
]);

Here, you would not only be able to filter based on genre or author, but you would also get a list of all the possible values for each attribute. You could display these on your search UI, allowing your end-users to select them.

To use the attributes for filtering only, you can use the filterOnly modifier:

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

Filter-only attributes are useful when you don’t need to offer a choice to the end-user. For example, if you had one page per author and wanted to automatically filter on it based on what page the user is visiting. It also improves performance because the engine doesn’t need to compile the facet counts.

You shouldn’t include colons (:) in attribute names that you want to use for faceting, because the filters syntax relies on that character as a delimiter.

Retrieving facets

To retrieve facets and their respective counts as part of the JSON response, you need to specify a list of facets in the facets parameter at query time.

For example, you can retrieve your books’ facets by specifying the following list:

1
2
3
$results = $index->search('query', [
  'facets' => ['author', 'genre']
]);

To extract all facet information, you can use a wildcard (*).

1
2
3
$results = $index->search('query', [
  'facets' => ['*']
]);

When the facets parameter is empty, the engine returns no facet information.

Faceting types and features

Conjunctive and disjunctive faceting

From a UI perspective, faceting is useful to filter results. We call this facet filtering, which means filtering based on facet values.

You can combine facet filters with AND (conjunctive) and OR (disjunctive) operators. When using these operators, the engine handles the facet counts differently to keep a consistent user experience. This doesn’t happen at the API level, but in our InstantSearch UI libraries.

Hierarchical facets

You can build a hierarchy in your facet values to enable multi-level navigation and filtering. This pattern is interesting to improve discoverability when you have deeply nested categories, as your users can browse up and down in the levels to refine their search.

For example, imagine a book available in Books > Science Fiction > Time Travel:

1
2
3
4
5
"categories": {
  "lvl0": "Books",
  "lvl1": "Books > Science Fiction",
  "lvl2": "Books > Science Fiction > Time Travel"
}

Or a book available in both Books > Science Fiction > Time Travel and Books > Literature & Fiction > Modernism:

1
2
3
4
5
"categories": {
  "lvl0": "Books",
  "lvl1": ["Books > Science Fiction", "Books > Literature & Fiction"],
  "lvl2": ["Books > Science Fiction > Time Travel", "Books > Literature & Fiction > Modernism "]
}

To help you build hierarchical faceting, we provide a hierarchicalMenu widget in our Instantsearch UI libraries.

You currently cannot do disjunctive faceting with hierarchical facets.

Contextual facet values and counts

Enabling faceting on attributes computes facet counts for each facet value, and the engine updates and returns the list of values and counts with each search result. It’s useful to provide the end-user with a relevant and contextual set of filters and information.

Approximative facet counts

When dealing with massive indices, the engine might need to make an approximation on facet counts to guarantee optimal performance. If you want to know whether the facet counts are exact, you can check the exhaustiveFacetsCount property in the JSON response.

Increasing the default limit

By default, the engine lets you retrieve 100 values per facet. If you need to increase this limit, you can use the maxValuesPerFacet parameter. The maximum is 1,000 facet values at a time.

1
2
3
$index->setSettings([
  'maxValuesPerFacet' => 1000
]);

Faceting on objectID

You can’t facet on the objectID attribute, and the engine ignores it if you declare it in attributesForFaceting. Faceting on a unique identifier makes little sense, though, because every facet count would be equal to one.

However, the engine implicitly treats the objectID attribute as a filter-only facet. You can filter on that attribute (even without declaring it in attributesForFaceting), but don’t get any facet counts.

Case sensitivity

Facets and facet filters are case-insensitive, except for facet filters on objectID.

Search for facet values

Sometimes you may have thousands of different values for a given facet attribute, and it would be impossible to display them all on the UI. Instead, you can leverage search_for_facet_values to let users search within a specific faceted attribute (e.g., brands, authors, or categories) without needing to create a separate index. It means that you can still display the first, most common values for each facet, but also let the user search for more.

By default, we return facet values sorted by count.

Declaring a searchable attribute for faceting

You can make a facet searchable via the dashboard (in the Configuration tab of the target index), or with the API:

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

Searching in facet values

In this example, the engine would return all the authors containing a match to the query “stephen”.

1
$index->searchForFacetValues("author", "stephen");

Increasing the default limit

By default, you can only retrieve 10 facet values at a time. You can raise this limit up to 100 by updating the maxFacetHits parameter.

1
2
3
$index->setSettings([
  'maxFacetHits' => 100
]);

Did you find this page helpful?