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

# Enhance search results with query-based rules

> Use rules to enhance search results based on user queries.

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>;

You can use rules to enhance the user experience based on what they search for.

For example, if you're building an app to search for airports,
Algolia's [geolocation feature](/doc/guides/managing-results/refine-results/geolocation) helpfully ranks results by proximity.
However, the nearest airport isn't necessarily the best choice.
In Paris, a search based on proximity might rank Le Bourget, a small airport for private jets, over large airports like Charles de Gaulle or Orly.

As a solution, you could prioritize other factors over [proximity](/doc/guides/managing-results/relevance-overview/in-depth/ranking-criteria#geo-if-applicable).
For example, you could rank airports by their number of airline connections.
However, if you also set a geolocation parameter like [`aroundLatLngViaIP`](/doc/api-reference/api-parameters/aroundLatLngViaIP),
proximity remains the primary factor in determining the order of search results.

A better solution is to create a rule so that when users search for a specific city or country,
it turns off the `aroundLatLngViaIP` parameter for that query.

## Before you begin

Before creating the rule, ensure that:

* `nb_airline_connections` is the [custom ranking](/doc/guides/managing-results/must-do/custom-ranking) attribute
* `city` and `country` are set as [attributes for faceting](/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting-with-dashboard), so you can detect whenever a query matches them

## Create the rule in the dashboard

This example assumes you're using the [sample dataset](#example-dataset).

### Custom ranking and attributes for faceting

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, click **Ranking and Sorting**.
5. Click **Add custom ranking attribute** and select the `nb_airline_connections` attribute from the drop-down menu.
6. Click **Facets**, under Filtering and faceting, then click **Add an Attribute** and select `country` and `city`  from the drop-down menu.
7. Save your changes.

### Rule

Use the dashboard to create a rule that detects matches in facets `city` and `country`, and changes the search parameters accordingly.

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

2. Select **Create your first rule** or **New rule**.

3. In the drop-down menu, click **Manual Editor**.

4. In the **Condition(s)** section, keep **Query** toggled on, click **Contains** in the drop-down menu, and select **country**. `{facet:country}` should appear in the input.

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

   1. Click **Add consequence** and select **Add Query Parameter**.
   2. In the input, add the JSON parameters to apply when a user query matches the rule: `{ "aroundLatLngViaIP": false }`

6. Save your changes.

7. Click **New Rule** and then **Manual Editor** again.

8. In the **Condition(s)** section, keep **Query** toggled on, click **Contains** in the drop-down menu, and select **city**. `{facet:city}` should appear in the input.

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

   1. Click **Add consequence** and select **Add Query Parameter**.
   2. In the input field that appears, add the JSON parameters to apply when a user query matches the rule: `{ "aroundLatLngViaIP": false }`

10. Save your changes.

## Create the rule with the API

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

Before creating the rule,
set custom ranking and the [attributes for faceting](/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting).

This example assumes you're using the [sample dataset](#example-dataset).

### Custom ranking and attributes for faceting

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SetSettingsAsync(
    "INDEX_NAME",
    new IndexSettings
    {
      CustomRanking = new List<string> { "desc(nb_airline_liaisons)" },
      AttributesForFaceting = new List<string> { "city, country" },
    }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.setSettings(
    indexName: "INDEX_NAME",
    indexSettings: IndexSettings(
      customRanking: [
        "desc(nb_airline_liaisons)",
      ],
      attributesForFaceting: [
        "city, country",
      ],
    ),
  );
  ```

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

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings(
    "INDEX_NAME",
    new IndexSettings()
      .setCustomRanking(Arrays.asList("desc(nb_airline_liaisons)"))
      .setAttributesForFaceting(Arrays.asList("city, country"))
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.setSettings({
    indexName: 'theIndexName',
    indexSettings: { customRanking: ['desc(nb_airline_liaisons)'], attributesForFaceting: ['city, country'] },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings =
        IndexSettings(
          customRanking = listOf("desc(nb_airline_liaisons)"),
          attributesForFaceting = listOf("city, country"),
        ),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->setSettings(
      'INDEX_NAME',
      ['customRanking' => [
          'desc(nb_airline_liaisons)',
      ],
          'attributesForFaceting' => [
              'city, country',
          ],
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "customRanking": [
              "desc(nb_airline_liaisons)",
          ],
          "attributesForFaceting": [
              "city, country",
          ],
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.set_settings(
    "INDEX_NAME",
    Algolia::Search::IndexSettings.new(
      custom_ranking: ["desc(nb_airline_liaisons)"],
      attributes_for_faceting: ["city, country"]
    )
  )
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(
        customRanking = Some(Seq("desc(nb_airline_liaisons)")),
        attributesForFaceting = Some(Seq("city, country"))
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.setSettings(
      indexName: "INDEX_NAME",
      indexSettings: IndexSettings(
          attributesForFaceting: ["city, country"],
          customRanking: ["desc(nb_airline_liaisons)"]
      )
  )
  ```
</CodeGroup>

### Create the rule

Use the [`batch-rules`](/doc/libraries/sdk/v1/methods/batch-rules) method to create a rule that detects matches in facets `city` and `country`, and changes the search parameters accordingly.

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SaveRulesAsync(
    "INDEX_NAME",
    new List<Rule>
    {
      new Rule
      {
        ObjectID = "country",
        Conditions = new List<Condition>
        {
          new Condition
          {
            Pattern = "{facet:country}",
            Anchoring = Enum.Parse<Anchoring>("Contains"),
          },
        },
        Consequence = new Consequence
        {
          Params = new ConsequenceParams { AroundLatLngViaIP = false },
        },
      },
      new Rule
      {
        ObjectID = "city",
        Conditions = new List<Condition>
        {
          new Condition
          {
            Pattern = "{facet:city}",
            Anchoring = Enum.Parse<Anchoring>("Contains"),
          },
        },
        Consequence = new Consequence
        {
          Params = new ConsequenceParams { AroundLatLngViaIP = false },
        },
      },
    }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.saveRules(
    indexName: "INDEX_NAME",
    rules: [
      Rule(
        objectID: "country",
        conditions: [
          Condition(
            pattern: "{facet:country}",
            anchoring: Anchoring.fromJson("contains"),
          ),
        ],
        consequence: Consequence(
          params: ConsequenceParams(
            aroundLatLngViaIP: false,
          ),
        ),
      ),
      Rule(
        objectID: "city",
        conditions: [
          Condition(
            pattern: "{facet:city}",
            anchoring: Anchoring.fromJson("contains"),
          ),
        ],
        consequence: Consequence(
          params: ConsequenceParams(
            aroundLatLngViaIP: false,
          ),
        ),
      ),
    ],
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SaveRules(client.NewApiSaveRulesRequest(
    "INDEX_NAME",
    []search.Rule{*search.NewEmptyRule().SetObjectID("country").SetConditions(
      []search.Condition{*search.NewEmptyCondition().SetPattern("{facet:country}").SetAnchoring(search.Anchoring("contains"))}).SetConsequence(
      search.NewEmptyConsequence().SetParams(
        search.NewEmptyConsequenceParams().SetAroundLatLngViaIP(false))), *search.NewEmptyRule().SetObjectID("city").SetConditions(
      []search.Condition{*search.NewEmptyCondition().SetPattern("{facet:city}").SetAnchoring(search.Anchoring("contains"))}).SetConsequence(
      search.NewEmptyConsequence().SetParams(
        search.NewEmptyConsequenceParams().SetAroundLatLngViaIP(false)))}))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.saveRules(
    "INDEX_NAME",
    Arrays.asList(
      new Rule()
        .setObjectID("country")
        .setConditions(Arrays.asList(new Condition().setPattern("{facet:country}").setAnchoring(Anchoring.CONTAINS)))
        .setConsequence(new Consequence().setParams(new ConsequenceParams().setAroundLatLngViaIP(false))),
      new Rule()
        .setObjectID("city")
        .setConditions(Arrays.asList(new Condition().setPattern("{facet:city}").setAnchoring(Anchoring.CONTAINS)))
        .setConsequence(new Consequence().setParams(new ConsequenceParams().setAroundLatLngViaIP(false)))
    )
  );
  ```

  ```js JavaScript theme={"system"}
  const response = await client.saveRules({
    indexName: 'INDEX_NAME',
    rules: [
      {
        objectID: 'country',
        conditions: [{ pattern: '{facet:country}', anchoring: 'contains' }],
        consequence: { params: { aroundLatLngViaIP: false } },
      },
      {
        objectID: 'city',
        conditions: [{ pattern: '{facet:city}', anchoring: 'contains' }],
        consequence: { params: { aroundLatLngViaIP: false } },
      },
    ],
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.saveRules(
      indexName = "INDEX_NAME",
      rules =
        listOf(
          Rule(
            objectID = "country",
            conditions =
              listOf(
                Condition(
                  pattern = "{facet:country}",
                  anchoring = Anchoring.entries.first { it.value == "contains" },
                )
              ),
            consequence = Consequence(params = ConsequenceParams(aroundLatLngViaIP = false)),
          ),
          Rule(
            objectID = "city",
            conditions =
              listOf(
                Condition(
                  pattern = "{facet:city}",
                  anchoring = Anchoring.entries.first { it.value == "contains" },
                )
              ),
            consequence = Consequence(params = ConsequenceParams(aroundLatLngViaIP = false)),
          ),
        ),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->saveRules(
      'INDEX_NAME',
      [
          ['objectID' => 'country',
              'conditions' => [
                  ['pattern' => '{facet:country}',
                      'anchoring' => 'contains',
                  ],
              ],
              'consequence' => ['params' => ['aroundLatLngViaIP' => false,
              ],
              ],
          ],

          ['objectID' => 'city',
              'conditions' => [
                  ['pattern' => '{facet:city}',
                      'anchoring' => 'contains',
                  ],
              ],
              'consequence' => ['params' => ['aroundLatLngViaIP' => false,
              ],
              ],
          ],
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.save_rules(
      index_name="INDEX_NAME",
      rules=[
          {
              "objectID": "country",
              "conditions": [
                  {
                      "pattern": "{facet:country}",
                      "anchoring": "contains",
                  },
              ],
              "consequence": {
                  "params": {
                      "aroundLatLngViaIP": False,
                  },
              },
          },
          {
              "objectID": "city",
              "conditions": [
                  {
                      "pattern": "{facet:city}",
                      "anchoring": "contains",
                  },
              ],
              "consequence": {
                  "params": {
                      "aroundLatLngViaIP": False,
                  },
              },
          },
      ],
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.save_rules(
    "INDEX_NAME",
    [
      Algolia::Search::Rule.new(
        algolia_object_id: "country",
        conditions: [Algolia::Search::Condition.new(pattern: "{facet:country}", anchoring: "contains")],
        consequence: Algolia::Search::Consequence.new(
          params: Algolia::Search::ConsequenceParams.new(around_lat_lng_via_ip: false)
        )
      ),
      Algolia::Search::Rule.new(
        algolia_object_id: "city",
        conditions: [Algolia::Search::Condition.new(pattern: "{facet:city}", anchoring: "contains")],
        consequence: Algolia::Search::Consequence.new(
          params: Algolia::Search::ConsequenceParams.new(around_lat_lng_via_ip: false)
        )
      )
    ]
  )
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.saveRules(
      indexName = "INDEX_NAME",
      rules = Seq(
        Rule(
          objectID = "country",
          conditions = Some(
            Seq(
              Condition(
                pattern = Some("{facet:country}"),
                anchoring = Some(Anchoring.withName("contains"))
              )
            )
          ),
          consequence = Consequence(
            params = Some(
              ConsequenceParams(
                aroundLatLngViaIP = Some(false)
              )
            )
          )
        ),
        Rule(
          objectID = "city",
          conditions = Some(
            Seq(
              Condition(
                pattern = Some("{facet:city}"),
                anchoring = Some(Anchoring.withName("contains"))
              )
            )
          ),
          consequence = Consequence(
            params = Some(
              ConsequenceParams(
                aroundLatLngViaIP = Some(false)
              )
            )
          )
        )
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.saveRules(
      indexName: "INDEX_NAME",
      rules: [
          Rule(objectID: "country", conditions: [SearchCondition(
              pattern: "{facet:country}",
              anchoring: SearchAnchoring.contains
          )], consequence: SearchConsequence(params: SearchConsequenceParams(aroundLatLngViaIP: false))),
          Rule(
              objectID: "city",
              conditions: [SearchCondition(pattern: "{facet:city}", anchoring: SearchAnchoring.contains)],
              consequence: SearchConsequence(params: SearchConsequenceParams(aroundLatLngViaIP: false))
          ),
      ]
  )
  ```
</CodeGroup>

## Query time

If a user query exactly matches a city or a country **in** your dataset,
the rule sets `aroundLatLngViaIP` to `false` overriding any other parameters in the query.

For example, if a user searches for "Paris" or "China", matching airports are ranked by `nb_airline_liaisons`.
When not searching for either a city or a country, airports are ranked by distance from the user's location.

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

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

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

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

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

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

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

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

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

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

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

## Example dataset

```json JSON icon=braces theme={"system"}
[
  {
    "name": "Orly",
    "city": "Paris",
    "country": "France",
    "_geoloc": { "lat": 48.725278, "lng": 2.359444 },
    "nb_airline_connections": 404
  },
  {
    "name": "Charles De Gaulle",
    "city": "Paris",
    "country": "France",
    "_geoloc": { "lat": 49.012779, "lng": 2.55 },
    "nb_airline_connections": 1041
  },
  {
    "name": "Le Bourget",
    "city": "Paris",
    "country": "France",
    "_geoloc": { "lat": 48.961487, "lng": 2.436966 },
    "nb_airline_connections": 0
  },
  {
    "name": "Ben Gurion",
    "city": "Tel-Aviv",
    "country": "Israel",
    "_geoloc": { "lat": 32.011389, "lng": 34.886667 },
    "nb_airline_connections": 271
  },
  {
    "name": "Haifa",
    "city": "Haifa",
    "country": "Israel",
    "_geoloc": { "lat": 32.809444, "lng": 35.043056 },
    "nb_airline_connections": 4
  },
  {
    "name": "Pudong",
    "city": "Shanghai",
    "country": "China",
    "_geoloc": { "lat": 31.143378, "lng": 121.805214 },
    "nb_airline_connections": 825
  },
  {
    "name": "Hongqiao Intl",
    "city": "Shanghai",
    "country": "China",
    "_geoloc": { "lat": 31.197875, "lng": 121.336319 },
    "nb_airline_connections": 411
  }
]
```

## See also

* [Geographical search with InstantSearch.js](/doc/guides/building-search-ui/ui-and-ux-patterns/geo-search/js)
* [Send and update your data](/doc/guides/sending-and-managing-data/send-and-update-your-data)
