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

# Deduplicate results with distinct

> Distinct deduplicates search results that have the same value for an attribute.

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 Application = () => <Tooltip tip="An Algolia application is a self-contained environment with its own indices, configuration, and API keys. Applications don't share data or settings with each other.">
    application
  </Tooltip>;

export const AlgoliaSearch = () => <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80" width="20" height="20" className="inline" fill="none" role="presentation" ariaLabel="Algolia Search">
    <circle cx="40" cy="32" r="28" fill="#5468FF"></circle>
    <rect x="30" y="22" width="20" height="20" rx="10" fill="#fff"></rect>
    <path d="M43 63.5 54.5 60l6 17h-12L43 63.5Z" fill="#36395A"></path>
  </svg>;

The `distinct` feature deduplicates search results by grouping <Records /> that share the same attribute value,
so your search results show one representative record per group instead of every matching record.

This is useful when:

* **[Handling item variations](#handle-item-variations):** if you sell t-shirts and every t-shirt has 10 color variants, show one color variant per design instead of all 10. This helps users discover more products (instead of variants of the same product). You can still show the available colors in the product details.
* **[Indexing long documents](/doc/guides/sending-and-managing-data/prepare-your-data/how-to/indexing-long-documents):** if you split a page into one record per section, a query might return multiple chunks from the same page. With `distinct`, only the best-matching chunk appears per page or section.

## Deduplicate results with distinct

To deduplicate search results, configure both:

* [`attributeForDistinct`](/doc/api-reference/api-parameters/attributeForDistinct): the attribute Algolia uses to group records.
* [`distinct`](/doc/api-reference/api-parameters/distinct): how many records to show from each group.

For example, if you set the `url` attribute as `attributeForDistinct`,
Algolia groups records with the same `url` value.

If you set `distinct` to `true`,
Algolia returns only the best matching record from each group.
You can also set `distinct` to a number to return more than one record from each group.

### Choose an attribute for grouping

Choose an attribute that has the same value for all records you want to group together.
Use an identifier instead of a display value if names, titles, or other aspects can change.
For example:

* For product variants, use a product identifier such as `product_id`, `design`, or `sku_group`.
* For job openings, use `company`.
* For long documents, use `url`, `page_id`, or `section_id`.

To define groups of records based on queries or matching filters, see [Smart Groups](/doc/guides/managing-results/compositions/smart-groups).

## Flatten your records

To use `distinct` and `attributeForDistinct` effectively,
flatten your records:

* Create one record for each searchable item.
* Repeat the grouping attribute in each record.

The following example shows the difference between nested and flat record structures.

### Nested records

```json JSON icon=braces theme={"system"}
[
  {
    "objectID": "design-1",
    "name": "Algolia Logo T-Shirt",
    "variants": [
      {
        "color": "red",
        "size": "S",
        "sku": "algolia-logo-red-s"
      },
      {
        "color": "blue",
        "size": "M",
        "sku": "algolia-logo-blue-m"
      }
    ]
  }
]
```

With this structure, when a query matches one variant, Algolia returns the whole t-shirt design with all its variants.
Each record represents a design, not an individual variant.

If you want users to search for specific variants, or if you want to show the best matching variant for each design, this structure doesn't support that use case.

### Flattened records

Instead of nested records, create one record for each variant and repeat the design information in each record:

```json JSON icon=braces theme={"system"}
[
  {
    "objectID": "algolia-logo-red-s",
    "design": "design-1",
    "name": "Algolia Logo T-Shirt",
    "color": "red",
    "size": "S",
    "sku": "algolia-logo-red-s"
  },
  {
    "objectID": "algolia-logo-blue-m",
    "design": "design-1",
    "name": "Algolia Logo T-Shirt",
    "color": "blue",
    "size": "M",
    "sku": "algolia-logo-blue-m"
  }
]
```

Each flattened record represents a single t-shirt variant.
The `design` attribute identifies variants that belong to the same design, which you can use as the attribute for `distinct`.

## Handle item variations

Consider a shop that sells t-shirts and sweatshirts in different designs and colors.
To deduplicate variants by design, create one record for each color variant.

The inventory has:

* Two t-shirt designs: A and B
* Two sweatshirt designs: C and D

Each design comes in different colors.

<img src="https://mintcdn.com/algolia/0u_XqgAn7MC5F_qG/images/guides/distinct/distinct.png?fit=max&auto=format&n=0u_XqgAn7MC5F_qG&q=85&s=e1097a0be7aab4e34f5e2d678df0caa0" alt="Diagram that shows t-shirts and sweatshirts grouped by design, with several color variants for each." width="1610" height="1244" data-path="images/guides/distinct/distinct.png" />

Each record contains the type, design, color, and thumbnail image:

```json JSON icon=braces theme={"system"}
[
  {
    "type": "t-shirt",
    "design": "B",
    "color": "blue",
    "thumbnail_url": "tshirt-B-blue.png"
  },
  {
    "type": "sweatshirt",
    "design": "C",
    "color": "red",
    "thumbnail_url": "sweatshirt-C-red.png"
  }
]
```

You can add all possible color variations to each record.
This makes all variants available for display in your UI,
for example, as color swatches below the product thumbnail.

```json JSON icon=braces theme={"system"}
[
  {
    "type": "t-shirt",
    "design": "B",
    "color": "blue",
    "thumbnail_url": "tshirt-B-blue.png",
    "color_variants": ["orange", "teal", "yellow", "red", "green"]
  },
  {
    "type": "t-shirt",
    "design": "B",
    "color": "orange",
    "thumbnail_url": "tshirt-B-orange.png",
    "color_variants": ["blue", "teal", "yellow", "red", "green"]
  }
]
```

Having one record per variation lets you add granular custom ranking attributes,
such as `number_of_sales`.

Use `distinct` with `design` as the `attributeForDistinct` to show fewer variants per design,
so users can browse a wider range of designs.

## Configure distinct in the dashboard

After flattening your records, configure `distinct` to group variants.

1. Go to the [Algolia dashboard](https://dashboard.algolia.com/explorer/browse) and select your Algolia <Application />.
2. On the left sidebar, select <AlgoliaSearch /> **Search**.
3. Select your Algolia index.
4. On the **Configuration** tab, select **Relevance essentials > Searchable attributes**.
5. Click **Add a Searchable Attribute** and add `design`, `type`, and `color` attributes.
6. Go to **Search behavior > Deduplication and Grouping**.
7. In the **Distinct** menu, select **true**.
8. In the **Attribute for Distinct** menu, select the `design` attribute.
9. Save your changes.

Now, the results include only one color variant per design.

To control which variant appears in the results,
add an attribute such as `number_of_sales` and use it in your [custom ranking](/doc/guides/managing-results/must-do/custom-ranking/how-to/configure-custom-ranking).

<img src="https://mintcdn.com/algolia/0u_XqgAn7MC5F_qG/images/guides/distinct/distinct-2.png?fit=max&auto=format&n=0u_XqgAn7MC5F_qG&q=85&s=3f49e025effdbaa5fbc6a24551a372f9" alt="Screenshot of search results showing one clothing variant for each design, with color swatches below each item." width="1580" height="517" data-path="images/guides/distinct/distinct-2.png" />

## Configure distinct with the API

Before deduplicating results,
restrict which attributes are searchable.
For example, searching the `thumbnail_url` and `color_variants` attributes can match queries that aren't relevant.
Set only `design`, `type`, and `color` as [`searchableAttributes`](/doc/api-reference/api-parameters/searchableAttributes).

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SetSettingsAsync(
    "INDEX_NAME",
    new IndexSettings
    {
      SearchableAttributes = new List<string> { "design", "type", "color" },
    }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.setSettings(
    indexName: "INDEX_NAME",
    indexSettings: IndexSettings(
      searchableAttributes: [
        "design",
        "type",
        "color",
      ],
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SetSettings(client.NewApiSetSettingsRequest(
    "INDEX_NAME",
    search.NewEmptyIndexSettings().SetSearchableAttributes(
      []string{"design", "type", "color"})))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings(
    "INDEX_NAME",
    new IndexSettings().setSearchableAttributes(Arrays.asList("design", "type", "color"))
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.setSettings({
    indexName: 'theIndexName',
    indexSettings: { searchableAttributes: ['design', 'type', 'color'] },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(searchableAttributes = listOf("design", "type", "color")),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->setSettings(
      'INDEX_NAME',
      ['searchableAttributes' => [
          'design',

          'type',

          'color',
      ],
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "searchableAttributes": [
              "design",
              "type",
              "color",
          ],
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.set_settings(
    "INDEX_NAME",
    Algolia::Search::IndexSettings.new(searchable_attributes: ["design", "type", "color"])
  )
  ```

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

  ```swift Swift theme={"system"}
  let response = try await client.setSettings(
      indexName: "INDEX_NAME",
      indexSettings: IndexSettings(searchableAttributes: ["design", "type", "color"])
  )
  ```
</CodeGroup>

Next, use the [`setSettings`](/doc/libraries/sdk/methods/search/set-settings) method to set `design` as [`attributeForDistinct`](/doc/api-reference/api-parameters/attributeForDistinct).

<Tip>
  To deduplicate all following search requests,
  set [`distinct`](/doc/api-reference/api-parameters/distinct) to `true` with `setSettings`.
</Tip>

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

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

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

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings(
    "INDEX_NAME",
    new IndexSettings().setAttributeForDistinct("design").setDistinct(Distinct.of(true))
  );
  ```

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

  ```kotlin Kotlin theme={"system"}
  var response =
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(attributeForDistinct = "design", distinct = Distinct.of(true)),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->setSettings(
      'INDEX_NAME',
      ['attributeForDistinct' => 'design',
          'distinct' => true,
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "attributeForDistinct": "design",
          "distinct": True,
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.set_settings(
    "INDEX_NAME",
    Algolia::Search::IndexSettings.new(attribute_for_distinct: "design", distinct: true)
  )
  ```

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

  ```swift Swift theme={"system"}
  let response = try await client.setSettings(
      indexName: "INDEX_NAME",
      indexSettings: IndexSettings(attributeForDistinct: "design", distinct: SearchDistinct.bool(true))
  )
  ```
</CodeGroup>

After setting `attributeForDistinct`,
you can also set `distinct` as a `search` method parameter:

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

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

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

  ```java Java theme={"system"}
  SearchResponse response = client.searchSingleIndex(
    "INDEX_NAME",
    new SearchParamsObject().setDistinct(Distinct.of(true)),
    Hit.class
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.searchSingleIndex({ indexName: 'indexName', searchParams: { distinct: true } });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.searchSingleIndex(
      indexName = "INDEX_NAME",
      searchParams = SearchParamsObject(distinct = Distinct.of(true)),
    )
  ```

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

  ```python Python theme={"system"}
  response = client.search_single_index(
      index_name="INDEX_NAME",
      search_params={
          "distinct": True,
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.search_single_index("INDEX_NAME", Algolia::Search::SearchParamsObject.new(distinct: true))
  ```

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

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

This deduplicates results only for the current search.

## See also

* [Structure ecommerce product records](/doc/guides/sending-and-managing-data/prepare-your-data/how-to/ecommerce-records)
