> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Faceting

> Algolia uses facets for categorizing and grouping your data. Users can use facets to refine their search.

export const Records = () => <Tooltip tip="A record is a searchable object in an Algolia index. Each record consists of named attributes." cta="Algolia records" href="/doc/guides/sending-and-managing-data/prepare-your-data#algolia-records">
    records
  </Tooltip>;

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </Tooltip>;

Facets let you create **categories on a select group of attributes so that users can refine their search**.
For example, on an <Index /> of books, helpful facets might be author and genre.
Algolia also calculates results for each facet.
It lets you display facets and facet counts so that users can filter results.

## What's a facet?

Think of facets as a set of filterable categories that allow users to refine results by multiple categories simultaneously.
Algolia derives these facets from attributes.

* For a book index, facets might be `author` or `genre`.
* For a luxury shop, facets might be `brand` or `designer`.

Algolia's faceting features let you:

* List all 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 attribute's value
* Enable search within an attribute's values ([search for facet values](#search-for-facet-values)).

## Difference between filters and facets

Filters and facets often get mixed up because there's much overlap, but [understanding the difference is essential](https://www.algolia.com/blog/ux/filters-vs-facets-in-site-search/). Both help to restrict a search to a subset of results.

* **Filters provide basic options to help narrow down search results.** Sometimes users don't see the filter restrictions, for example, when automatically filtering the records they're allowed to see based on their user ID.
* **Facets help users refine their search using several categories simultaneously.** Faceting is still filtering but displays facets to allow users to choose from a set of useful values, features, and counts.

## How to configure faceting

You can configure faceting from the dashboard or the API, but the overall process is the same:

1. [Declare attributes for faceting](/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting)
2. Retrieve facets from the API (see the following section).

## Retrieve facets

To run the code examples on this page, [install the latest API client](/doc/libraries/sdk/install).

To retrieve facets and their respective counts as part of the JSON response,
specify a list of facets in the [`facets`](/doc/api-reference/api-parameters/facets) parameter at query time.

For example, retrieve your books' facets by specifying the following list:

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SearchSingleIndexAsync<Hit>(
    "INDEX_NAME",
    new SearchParams(
      new SearchParamsObject
      {
        Facets = new List<string> { "author", "genre" },
      }
    )
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.searchSingleIndex(
    indexName: "INDEX_NAME",
    searchParams: SearchParamsObject(
      facets: [
        "author",
        "genre",
      ],
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(
    "INDEX_NAME").WithSearchParams(search.SearchParamsObjectAsSearchParams(
    search.NewEmptySearchParamsObject().SetFacets(
      []string{"author", "genre"}))))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  SearchResponse response = client.searchSingleIndex(
    "INDEX_NAME",
    new SearchParamsObject().setFacets(Arrays.asList("author", "genre")),
    Hit.class
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.searchSingleIndex({
    indexName: 'indexName',
    searchParams: { facets: ['author', 'genre'] },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.searchSingleIndex(
      indexName = "INDEX_NAME",
      searchParams = SearchParamsObject(facets = listOf("author", "genre")),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->searchSingleIndex(
      'INDEX_NAME',
      ['facets' => [
          'author',

          'genre',
      ],
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.search_single_index(
      index_name="INDEX_NAME",
      search_params={
          "facets": [
              "author",
              "genre",
          ],
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.search_single_index(
    "INDEX_NAME",
    Algolia::Search::SearchParamsObject.new(facets: ["author", "genre"])
  )
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.searchSingleIndex(
      indexName = "INDEX_NAME",
      searchParams = Some(
        SearchParamsObject(
          facets = Some(Seq("author", "genre"))
        )
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response: SearchResponse<Hit> = try await client.searchSingleIndex(
      indexName: "INDEX_NAME",
      searchParams: SearchSearchParams.searchSearchParamsObject(SearchSearchParamsObject(facets: [
          "author",
          "genre",
      ]))
  )
  ```
</CodeGroup>

To extract all facet information, use the wildcard character (`*`).

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SearchSingleIndexAsync<Hit>(
    "INDEX_NAME",
    new SearchParams(new SearchParamsObject { Facets = new List<string> { "*" } })
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.searchSingleIndex(
    indexName: "INDEX_NAME",
    searchParams: SearchParamsObject(
      facets: [
        "*",
      ],
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(
    "INDEX_NAME").WithSearchParams(search.SearchParamsObjectAsSearchParams(
    search.NewEmptySearchParamsObject().SetFacets(
      []string{"*"}))))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  SearchResponse response = client.searchSingleIndex(
    "INDEX_NAME",
    new SearchParamsObject().setFacets(Arrays.asList("*")),
    Hit.class
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.searchSingleIndex({ indexName: 'indexName', searchParams: { facets: ['*'] } });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.searchSingleIndex(
      indexName = "INDEX_NAME",
      searchParams = SearchParamsObject(facets = listOf("*")),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->searchSingleIndex(
      'INDEX_NAME',
      ['facets' => [
          '*',
      ],
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.search_single_index(
      index_name="INDEX_NAME",
      search_params={
          "facets": [
              "*",
          ],
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.search_single_index("INDEX_NAME", Algolia::Search::SearchParamsObject.new(facets: ["*"]))
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.searchSingleIndex(
      indexName = "INDEX_NAME",
      searchParams = Some(
        SearchParamsObject(
          facets = Some(Seq("*"))
        )
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response: SearchResponse<Hit> = try await client.searchSingleIndex(
      indexName: "INDEX_NAME",
      searchParams: SearchSearchParams.searchSearchParamsObject(SearchSearchParamsObject(facets: ["*"]))
  )
  ```
</CodeGroup>

## Faceting types and features

### Conjunctive and disjunctive faceting

Filtering based on facet values is helpful for users since it allows them to find specific,
targeted results in a way that isn't possible with one-size-fits-all filters.

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 the [InstantSearch libraries](/doc/guides/building-search-ui/what-is-instantsearch/js).

### 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, consider a book available in **Books > Science Fiction > Time Travel**:

```json JSON icon=braces theme={"system"}
{
  "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 and Fiction > Modernism**:

```json JSON icon=braces theme={"system"}
{
  "categories": {
    "lvl0": "Books",
    "lvl1": ["Books > Science Fiction", "Books > Literature and Fiction"],
    "lvl2": [
      "Books > Science Fiction > Time Travel",
      "Books > Literature and Fiction > Modernism "
    ]
  }
}
```

The [`hierarchicalMenu`](/doc/api-reference/widgets/hierarchical-menu/js) widget from the [InstantSearch libraries](/doc/guides/building-search-ui/what-is-instantsearch/js) helps you to build hierarchical faceting.

<Note>
  Disjunctive facets with hierarchical facets aren't possible.
  Hierarchical facets with many nested attributes have many different facet names.
  This adds a lot of metadata that needs to be processed.
  This can lead to poor search performance, even if you don't reference these facets directly.
</Note>

### 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 helpful to offer users a relevant and contextual set of filters and information.

### How the engine approximates facet counts

When dealing with massive indices, the engine might need to approximate facet counts to guarantee optimal performance.
To see if the facet counts are exact, check the `exhaustiveFacetsCount` property in the JSON response.

### Increase the default limit

By default, the engine lets you retrieve 100 values per facet.
If you need to increase this limit, use the [`maxValuesPerFacet`](/doc/api-reference/api-parameters/maxValuesPerFacet) parameter.
The maximum is 1,000 facet values at a time.

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SetSettingsAsync(
    "INDEX_NAME",
    new IndexSettings { MaxValuesPerFacet = 1000 }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.setSettings(
    indexName: "INDEX_NAME",
    indexSettings: IndexSettings(
      maxValuesPerFacet: 1000,
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SetSettings(client.NewApiSetSettingsRequest(
    "INDEX_NAME",
    search.NewEmptyIndexSettings().SetMaxValuesPerFacet(1000)))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings("INDEX_NAME", new IndexSettings().setMaxValuesPerFacet(1000));
  ```

  ```js JavaScript theme={"system"}
  const response = await client.setSettings({ indexName: 'theIndexName', indexSettings: { maxValuesPerFacet: 1000 } });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(maxValuesPerFacet = 1000),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->setSettings(
      'INDEX_NAME',
      ['maxValuesPerFacet' => 1000,
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "maxValuesPerFacet": 1000,
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.set_settings("INDEX_NAME", Algolia::Search::IndexSettings.new(max_values_per_facet: 1000))
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(
        maxValuesPerFacet = Some(1000)
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.setSettings(
      indexName: "INDEX_NAME",
      indexSettings: IndexSettings(maxValuesPerFacet: 1000)
  )
  ```
</CodeGroup>

### Faceting on object ID

You can't facet on the `objectID` attribute, and the engine ignores it if you declare it in [`attributesForFaceting`](/doc/api-reference/api-parameters/attributesForFaceting). Faceting on a unique identifier makes little sense, though, because every facet count would be 1.

<Info>
  The engine treats the `objectID` attribute as a filter-only facet.
  You can filter on that attribute (even without declaring it in `attributesForFaceting` but not get any facet counts.
</Info>

### Attributes are case-sensitive

The attribute names you declare in [`attributesForFaceting`](/doc/api-reference/api-parameters/attributesForFaceting) are case-sensitive: **they must exactly match the attribute names in your records**. The [`facetFilters`](/doc/api-reference/api-parameters/facetFilters) and [`filters`](/doc/api-reference/api-parameters/filters) parameters are only case-insensitive for values.

For example, if your records include an attribute named `color`, with values such as "blue", "red", and "green", you must declare `color` (not `Color`) within your [`attributesForFaceting`](/doc/api-reference/api-parameters/attributesForFaceting). However, you can facet and filter using `color:BLUE`, `color:Blue`, or `color:blue`.

As an exception, **[`facetFilters`](/doc/api-reference/api-parameters/facetFilters) and [`filters`](/doc/api-reference/api-parameters/filters) are case-sensitive when filtering on `objectID`**. For example, `objectID:abc` only returns the record with that specific `objectID`, not one with `objectID:ABC`.

## 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 in your user interface (see the [facet display](/doc/guides/building-search-ui/ui-and-ux-patterns/facet-display/js) guide for more information). Instead, use [`search_for_facet_values`](/doc/libraries/sdk/v1/methods/search-for-facet-values) to let users search within a specific faceted attribute (for example, `brands`, `authors`, or `categories`) without needing to create a separate index. It means you can still display the first, most common values for each facet but also let users search for more.

By default, returned facet values are sorted by count.

<Note>
  Facet queries only match [prefixes](/doc/guides/managing-results/optimize-search-results/override-search-engine-defaults/in-depth/prefix-searching), [typos](/doc/guides/managing-results/optimize-search-results/typo-tolerance), and [exact](/doc/guides/managing-results/optimize-search-results/override-search-engine-defaults/in-depth/adjust-exact-settings).
</Note>

### Search for facet values

In this example, Algolia returns all the authors matching the query "stephen".

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SearchForFacetValuesAsync(
    "INDEX_NAME",
    "author",
    new SearchForFacetValuesRequest { FacetQuery = "stephen" }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.searchForFacetValues(
    indexName: "INDEX_NAME",
    facetName: "author",
    searchForFacetValuesRequest: SearchForFacetValuesRequest(
      facetQuery: "stephen",
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SearchForFacetValues(client.NewApiSearchForFacetValuesRequest(
    "INDEX_NAME", "author").WithSearchForFacetValuesRequest(
    search.NewEmptySearchForFacetValuesRequest().SetFacetQuery("stephen")))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  SearchForFacetValuesResponse response = client.searchForFacetValues(
    "INDEX_NAME",
    "author",
    new SearchForFacetValuesRequest().setFacetQuery("stephen")
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.searchForFacetValues({
    indexName: 'indexName',
    facetName: 'author',
    searchForFacetValuesRequest: { facetQuery: 'stephen' },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.searchForFacetValues(
      indexName = "INDEX_NAME",
      facetName = "author",
      searchForFacetValuesRequest = SearchForFacetValuesRequest(facetQuery = "stephen"),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->searchForFacetValues(
      'INDEX_NAME',
      'author',
      ['facetQuery' => 'stephen',
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.search_for_facet_values(
      index_name="INDEX_NAME",
      facet_name="author",
      search_for_facet_values_request={
          "facetQuery": "stephen",
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.search_for_facet_values(
    "INDEX_NAME",
    "author",
    Algolia::Search::SearchForFacetValuesRequest.new(facet_query: "stephen")
  )
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.searchForFacetValues(
      indexName = "INDEX_NAME",
      facetName = "author",
      searchForFacetValuesRequest = Some(
        SearchForFacetValuesRequest(
          facetQuery = Some("stephen")
        )
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.searchForFacetValues(
      indexName: "INDEX_NAME",
      facetName: "author",
      searchForFacetValuesRequest: SearchForFacetValuesRequest(facetQuery: "stephen")
  )
  ```
</CodeGroup>

### Increase the default limit

By default, you retrieve ten facet values at a time.
You can raise this limit up to 100 by updating the [`maxFacetHits`](/doc/api-reference/api-parameters/maxFacetHits) parameter.

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SetSettingsAsync(
    "INDEX_NAME",
    new IndexSettings { MaxFacetHits = 100 }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.setSettings(
    indexName: "INDEX_NAME",
    indexSettings: IndexSettings(
      maxFacetHits: 100,
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SetSettings(client.NewApiSetSettingsRequest(
    "INDEX_NAME",
    search.NewEmptyIndexSettings().SetMaxFacetHits(100)))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings("INDEX_NAME", new IndexSettings().setMaxFacetHits(100));
  ```

  ```js JavaScript theme={"system"}
  const response = await client.setSettings({ indexName: 'theIndexName', indexSettings: { maxFacetHits: 100 } });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(maxFacetHits = 100),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->setSettings(
      'INDEX_NAME',
      ['maxFacetHits' => 100,
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "maxFacetHits": 100,
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.set_settings("INDEX_NAME", Algolia::Search::IndexSettings.new(max_facet_hits: 100))
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(
        maxFacetHits = Some(100)
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.setSettings(
      indexName: "INDEX_NAME",
      indexSettings: IndexSettings(maxFacetHits: 100)
  )
  ```
</CodeGroup>
