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

# Searching by SKU

> Configure Algolia to make searching and filtering by SKUs and other numbers easier.

export const SearchQuery = () => <Tooltip tip="The text users enter into a search box. In the Search API, this corresponds to the query parameter. A search query is often used with filters, facets, and other parameters, but these aren't part of the query text itself.">
    search query
  </Tooltip>;

Business-to-business (B2B) buyers know what they need to buy and often search using precise product identifiers,
such as stock keeping units (SKU).
Or, they search for a product that meets strict specifications,
which would match several items in your catalog.
This guide describes how to set up Algolia to make searching and filtering by numbers easier.

## Turn off typo tolerance when searching by SKU

Algolia supports searching by SKU and other numbers by default,
if you include them as [searchable attributes](/doc/guides/managing-results/must-do/searchable-attributes).
By default, [typo tolerance](/doc/guides/managing-results/optimize-search-results/typo-tolerance) is turned on for numbers as well.
That's helpful when you don't want to limit the search results to exactly matching numbers,
for example, when searching for product variants or physical sizes.
When searching by SKU however,
it's better to turn off typo tolerance to allow for more precise searching.
If you add your SKU attribute to [`disableTypoToleranceOnAttributes`](/doc/api-reference/api-parameters/disableTypoToleranceOnAttributes), the search results only include products with exactly matching SKU.

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

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

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

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings(
    "INDEX_NAME",
    new IndexSettings().setDisableTypoToleranceOnAttributes(Arrays.asList("serial_number"))
  );
  ```

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

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

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

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "disableTypoToleranceOnAttributes": [
              "serial_number",
          ],
      },
  )
  ```

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

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

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

## Search in hyphenated attributes

By default, Algolia regards hyphens as separators, so searching for "123-X-456" and "123 X 456" returns the same results.
If you also want to allow searching for the number without spaces,
for example, "123X456",
it's important to [consider all variations](/doc/guides/managing-results/optimize-search-results/typo-tolerance/how-to/how-to-search-in-hyphenated-attributes#include-all-possible-formats).

## Detect searching intent with rules

You can guide buyers effectively by using rules to detect keywords in a <SearchQuery />.
For more information, see:

* [Rules overview](/doc/guides/managing-results/rules/rules-overview)
* [Detect keywords](/doc/guides/managing-results/rules/detecting-intent/how-to/detecting-keywords)

### Let users search by custom aliases for products

B2B buyers often return to buy the same products.
Typing or copying SKUs or other lengthy product identifiers every time can be tedious and error-prone.
Some ecommerce platforms allow buyers to save a custom alias, or reference, for an item.
With Algolia, you can use Rules to support searching by a custom alias to speed up the search.

For example, the buyer can save an alias `my_product` for the product with the ID "123-456-789".
You can create a rule that detects the alias and replaces it with the product ID.
When the buyer searches for `my_product`, Algolia applies the rule and returns the product matching the SKU.

```js JavaScript icon=code theme={"system"}
const rule = {
  objectID: 'user_123_alias_1',
  conditions: [
    {
      pattern: 'my_product',
      anchoring: 'contains',
      context: 'user_123'
    }
  ],
  consequence: {
    params: {
      query: {
        type: 'replace',
        delete: 'my_product',
        insert: '123-456-789',
      }
    },
  },
}
```

Each buyer defines their own aliases.
To apply the rule specific to each buyer,
you can use [`ruleContexts`](/doc/api-reference/api-parameters/ruleContexts) when searching.
For example, using one of the API clients:

<CodeGroup>
  ```cs C# theme={"system"}
  namespace Algolia;

  using System;
  using System.Collections.Generic;
  using System.Net.Http;
  using System.Text.Json;
  using Algolia.Search.Clients;
  using Algolia.Search.Http;
  using Algolia.Search.Models.Search;

  class SearchWithRuleContextBuyer
  {
    private static string GetBuyerAccountId()
    {
      return ""; // Implement your logic here
    }

    async Task Main(string[] args)
    {
      var client = new SearchClient(new SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY"));
      // get the buyer account information
      var buyer = GetBuyerAccountId();
      var searchParams = new SearchParams(
        new SearchParamsObject { Query = "SEARCH_QUERY", RuleContexts = [buyer] }
      );

      await client.SearchSingleIndexAsync<Hit>("INDEX_NAME", searchParams);
    }
  }

  ```

  ```dart Dart theme={"system"}
  import 'package:algolia_client_search/algolia_client_search.dart';

  String getBuyerAccountId() {
    return ""; // Implement your logic here
  }

  void searchWithRuleContextBuyer() async {
    final client =
        SearchClient(appId: 'ALGOLIA_APPLICATION_ID', apiKey: 'ALGOLIA_API_KEY');

    // get the buyer account information
    final buyer = getBuyerAccountId();
    final searchParams =
        SearchParamsObject(query: "SEARCH_QUERY", ruleContexts: [buyer]);

    await client.searchSingleIndex(
      indexName: "INDEX_NAME",
      searchParams: searchParams,
    );
  }

  ```

  ```go Go theme={"system"}
  package main

  import (
  	"github.com/algolia/algoliasearch-client-go/v4/algolia/search"
  )

  func getBuyerAccountID() (string, error) {
  	return "", nil // Implement your logic here
  }

  func searchWithRuleContextBuyer() {
  	client, err := search.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
  	if err != nil {
  		// The client can fail to initialize if you pass an invalid parameter.
  		panic(err)
  	}

  	// get the buyer account information
  	buyer, err := getBuyerAccountID()
  	if err != nil {
  		panic(err)
  	}

  	searchParams := search.SearchParamsObjectAsSearchParams(
  		search.NewSearchParamsObject().
  			SetQuery("SEARCH_QUERY").
  			SetRuleContexts([]string{buyer}),
  	)

  	_, err = client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(
  		"INDEX_NAME").WithSearchParams(searchParams))
  	if err != nil {
  		panic(err)
  	}
  }

  ```

  ```java Java theme={"system"}
  package com.algolia;

  import com.algolia.api.SearchClient;
  import com.algolia.config.*;
  import com.algolia.model.search.*;
  import java.util.List;

  public class searchWithRuleContextBuyer {

    private static String getBuyerAccountId() {
      return ""; // Implement your logic here
    }

    public static void main(String[] args) throws Exception {
      try (SearchClient client = new SearchClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")) {
        // get the buyer account information
        String buyer = getBuyerAccountId();
        SearchParams searchParams = new SearchParamsObject().setQuery("SEARCH_QUERY").setRuleContexts(List.of(buyer));

        client.searchSingleIndex("INDEX_NAME", searchParams, Hit.class);
      } catch (Exception e) {
        System.out.println("An error occurred: " + e.getMessage());
      }
    }
  }

  ```

  ```js JavaScript theme={"system"}
  import { algoliasearch } from 'algoliasearch';

  import type { SearchParams } from 'algoliasearch';

  const getBuyerAccountId = () => {
    return ''; // Implement your logic here
  };

  const client = algoliasearch('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY');

  // get the buyer account information
  const buyer = getBuyerAccountId();
  const searchParams: SearchParams = {
    query: 'SEARCH_QUERY',
    ruleContexts: [buyer],
  };

  await client.searchSingleIndex({ indexName: 'indexName', searchParams: searchParams });

  ```

  ```kotlin Kotlin theme={"system"}
  import com.algolia.client.api.SearchClient
  import com.algolia.client.configuration.*
  import com.algolia.client.extensions.*
  import com.algolia.client.model.search.*
  import com.algolia.client.transport.*

  val getBuyerAccountId: () -> String = {
    "" // Implement your logic here
  }

  suspend fun searchWithRuleContextBuyer() {
    val client = SearchClient(appId = "ALGOLIA_APPLICATION_ID", apiKey = "ALGOLIA_API_KEY")

    // get the buyer account information
    val buyer = getBuyerAccountId()
    val searchParams = SearchParamsObject(query = "SEARCH_QUERY", ruleContexts = listOf(buyer))

    client.searchSingleIndex(indexName = "INDEX_NAME", searchParams = searchParams)
  }

  ```

  ```php PHP theme={"system"}
  <?php

  require __DIR__.'/../vendor/autoload.php';
  use Algolia\AlgoliaSearch\Api\SearchClient;
  use Algolia\AlgoliaSearch\Model\Search\SearchParamsObject;

  $getBuyerAccountId = function (): string {
      // Implement your logic here
      return '';
  };

  $client = SearchClient::create('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY');

  // get the buyer account information
  $buyer = $getBuyerAccountId();
  $searchParams = (new SearchParamsObject())
      ->setQuery('SEARCH_QUERY')
      ->setRuleContexts([$buyer])
  ;

  $client->searchSingleIndex(
      'INDEX_NAME',
      $searchParams,
  );

  ```

  ```python Python theme={"system"}
  from algoliasearch.search.client import SearchClientSync

  from algoliasearch.search.models.search_params import SearchParams


  def _get_buyer_account_id() -> str:
      # Implement your logic here
      return ""


  _client = SearchClientSync("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")


  # get the buyer account information
  buyer = _get_buyer_account_id()
  search_params = SearchParams(
      query="SEARCH_QUERY",
      rule_contexts=[buyer],
  )

  _client.search_single_index(
      index_name="INDEX_NAME",
      search_params=search_params,
  )

  ```

  ```ruby Ruby theme={"system"}
  require "algolia"

  def get_buyer_account_id
    # Implement your logic here
    ""
  end

  client = Algolia::SearchClient.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")

  # get the buyer account information
  buyer = get_buyer_account_id
  search_params = Algolia::Search::SearchParamsObject.new(
    query: "SEARCH_QUERY",
    rule_contexts: [buyer]
  )

  client.search_single_index("INDEX_NAME", search_params)

  ```

  ```scala Scala theme={"system"}
  import scala.concurrent.Future
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent.Await
  import scala.concurrent.duration.Duration

  import algoliasearch.api.SearchClient
  import algoliasearch.config.*
  import algoliasearch.extension.SearchClientExtensions
  import algoliasearch.search.SearchParamsObject

  val getBuyerAccountId: () => String = () => {
    "" // Implement your logic here
  }

  def searchWithRuleContextBuyer(): Future[Unit] = {
    val client = SearchClient(appId = "ALGOLIA_APPLICATION_ID", apiKey = "ALGOLIA_API_KEY")

    // get the buyer account information
    val buyer = getBuyerAccountId()
    val searchParams = SearchParamsObject(query = Some("SEARCH_QUERY"), ruleContexts = Some(Seq(buyer)))

    Await.result(
      client
        .searchSingleIndex(
          indexName = "INDEX_NAME",
          searchParams = Some(searchParams)
        )
        .map(_ => Future.unit),
      Duration(5, "sec")
    )
  }

  ```

  ```swift Swift theme={"system"}
  import Foundation
  #if os(Linux) // For linux interop
      import FoundationNetworking
  #endif

  import AlgoliaCore
  import AlgoliaSearch

  let getBuyerAccountId = { "" } // Implement your logic here

  func searchWithRuleContextBuyer() async throws {
      let client = try SearchClient(appID: "ALGOLIA_APPLICATION_ID", apiKey: "ALGOLIA_API_KEY")

      // get the buyer account information
      let buyer = getBuyerAccountId()
      let searchParams = SearchSearchParams.searchSearchParamsObject(
          SearchSearchParamsObject(query: "SEARCH_QUERY", ruleContexts: [buyer])
      )

      let response: SearchResponse<Hit> = try await client.searchSingleIndex(
          indexName: "INDEX_NAME",
          searchParams: searchParams
      )
      print(response)
  }

  ```
</CodeGroup>

For more information, see:

* [Using rule contexts to customize search results by device](/doc/guides/managing-results/rules/rules-overview/how-to/customize-search-results-by-platform)
* [`ruleContexts`](/doc/api-reference/api-parameters/ruleContexts)

### Guide users by increasing search precision

For example, if a buyer searches for "article ref21", they might look for an item that starts with the number "21".
If that's the case, you can create a Rule to increase the precision of the search, by:

* Removing the keyword "article"
* Restricting the searchable attributes to the title and ID

#### Define a rule using the API clients

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SaveRuleAsync(
    "INDEX_NAME",
    "article-rule",
    new Rule
    {
      ObjectID = "article-rule",
      Conditions = new List<Condition>
      {
        new Condition { Pattern = "article", Anchoring = Enum.Parse<Anchoring>("StartsWith") },
      },
      Consequence = new Consequence
      {
        Params = new ConsequenceParams
        {
          Query = new ConsequenceQuery(
            new ConsequenceQueryObject
            {
              Edits = new List<Edit>
              {
                new Edit { Type = Enum.Parse<EditType>("Remove"), Delete = "article" },
              },
            }
          ),
          RestrictSearchableAttributes = new List<string> { "title", "book_id" },
        },
      },
    }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.saveRule(
    indexName: "INDEX_NAME",
    objectID: "article-rule",
    rule: Rule(
      objectID: "article-rule",
      conditions: [
        Condition(
          pattern: "article",
          anchoring: Anchoring.fromJson("startsWith"),
        ),
      ],
      consequence: Consequence(
        params: ConsequenceParams(
          query: ConsequenceQueryObject(
            edits: [
              Edit(
                type: EditType.fromJson("remove"),
                delete: "article",
              ),
            ],
          ),
          restrictSearchableAttributes: [
            "title",
            "book_id",
          ],
        ),
      ),
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SaveRule(client.NewApiSaveRuleRequest(
    "INDEX_NAME", "article-rule",
    search.NewEmptyRule().SetObjectID("article-rule").SetConditions(
      []search.Condition{*search.NewEmptyCondition().SetPattern("article").SetAnchoring(search.Anchoring("startsWith"))}).SetConsequence(
      search.NewEmptyConsequence().SetParams(
        search.NewEmptyConsequenceParams().SetQuery(search.ConsequenceQueryObjectAsConsequenceQuery(
          search.NewEmptyConsequenceQueryObject().SetEdits(
            []search.Edit{
              *search.NewEmptyEdit().SetType(search.EditType("remove")).SetDelete("article"),
            }),
        )).SetRestrictSearchableAttributes(
          []string{"title", "book_id"})))))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.saveRule(
    "INDEX_NAME",
    "article-rule",
    new Rule()
      .setObjectID("article-rule")
      .setConditions(Arrays.asList(new Condition().setPattern("article").setAnchoring(Anchoring.STARTS_WITH)))
      .setConsequence(
        new Consequence().setParams(
          new ConsequenceParams()
            .setQuery(new ConsequenceQueryObject().setEdits(Arrays.asList(new Edit().setType(EditType.REMOVE).setDelete("article"))))
            .setRestrictSearchableAttributes(Arrays.asList("title", "book_id"))
        )
      )
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.saveRule({
    indexName: 'indexName',
    objectID: 'article-rule',
    rule: {
      objectID: 'article-rule',
      conditions: [{ pattern: 'article', anchoring: 'startsWith' }],
      consequence: {
        params: {
          query: { edits: [{ type: 'remove', delete: 'article' }] },
          restrictSearchableAttributes: ['title', 'book_id'],
        },
      },
    },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.saveRule(
      indexName = "INDEX_NAME",
      objectID = "article-rule",
      rule =
        Rule(
          objectID = "article-rule",
          conditions =
            listOf(
              Condition(
                pattern = "article",
                anchoring = Anchoring.entries.first { it.value == "startsWith" },
              )
            ),
          consequence =
            Consequence(
              params =
                ConsequenceParams(
                  query =
                    ConsequenceQueryObject(
                      edits =
                        listOf(
                          Edit(
                            type = EditType.entries.first { it.value == "remove" },
                            delete = "article",
                          )
                        )
                    ),
                  restrictSearchableAttributes = listOf("title", "book_id"),
                )
            ),
        ),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->saveRule(
      'INDEX_NAME',
      'article-rule',
      ['objectID' => 'article-rule',
          'conditions' => [
              ['pattern' => 'article',
                  'anchoring' => 'startsWith',
              ],
          ],
          'consequence' => ['params' => ['query' => ['edits' => [
              ['type' => 'remove',
                  'delete' => 'article',
              ],
          ],
          ],
              'restrictSearchableAttributes' => [
                  'title',

                  'book_id',
              ],
          ],
          ],
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.save_rule(
      index_name="INDEX_NAME",
      object_id="article-rule",
      rule={
          "objectID": "article-rule",
          "conditions": [
              {
                  "pattern": "article",
                  "anchoring": "startsWith",
              },
          ],
          "consequence": {
              "params": {
                  "query": {
                      "edits": [
                          {
                              "type": "remove",
                              "delete": "article",
                          },
                      ],
                  },
                  "restrictSearchableAttributes": [
                      "title",
                      "book_id",
                  ],
              },
          },
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.save_rule(
    "INDEX_NAME",
    "article-rule",
    Algolia::Search::Rule.new(
      algolia_object_id: "article-rule",
      conditions: [Algolia::Search::Condition.new(pattern: "article", anchoring: "startsWith")],
      consequence: Algolia::Search::Consequence.new(
        params: Algolia::Search::ConsequenceParams.new(
          query: Algolia::Search::ConsequenceQueryObject.new(
            edits: [Algolia::Search::Edit.new(type: "remove", delete: "article")]
          ),
          restrict_searchable_attributes: ["title", "book_id"]
        )
      )
    )
  )
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.saveRule(
      indexName = "INDEX_NAME",
      objectID = "article-rule",
      rule = Rule(
        objectID = "article-rule",
        conditions = Some(
          Seq(
            Condition(
              pattern = Some("article"),
              anchoring = Some(Anchoring.withName("startsWith"))
            )
          )
        ),
        consequence = Consequence(
          params = Some(
            ConsequenceParams(
              query = Some(
                ConsequenceQueryObject(
                  edits = Some(
                    Seq(
                      Edit(
                        `type` = Some(EditType.withName("remove")),
                        delete = Some("article")
                      )
                    )
                  )
                )
              ),
              restrictSearchableAttributes = Some(Seq("title", "book_id"))
            )
          )
        )
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.saveRule(
      indexName: "INDEX_NAME",
      objectID: "article-rule",
      rule: Rule(
          objectID: "article-rule",
          conditions: [SearchCondition(pattern: "article", anchoring: SearchAnchoring.startsWith)],
          consequence: SearchConsequence(params: SearchConsequenceParams(
              restrictSearchableAttributes: ["title", "book_id"],
              query: SearchConsequenceQuery
                  .searchConsequenceQueryObject(SearchConsequenceQueryObject(edits: [SearchEdit(
                      type: SearchEditType.remove,
                      delete: "article"
                  )]))
          ))
      )
  )
  ```
</CodeGroup>

#### Define a rule using the Algolia dashboard

1. Go to the **[Rules](https://dashboard.algolia.com/rules)** page in the Algolia dashboard.

2. Click the **New rule** button.

3. Select **Create your first rule** or **New rule** and select **Manual Editor**.

4. In the **Condition(s)** section, keep **Query** toggled on, select **Contains**,
   and enter `article` in the input.

5. In the **Consequence(s)** section:

   1. Click the **Add consequence** button and select **Add Query Parameter**.
   2. In the input field that appears, enter the JSON search parameter you want to add.
      For example, `{ "restrictSearchableAttributes": ["title","id"] }`.
   3. Click the **Add consequence** button again and select **Remove Word**.
   4. Enter `article` in the input field.

6. Save your changes.
