Muokkaa

Jaa


Rewrite queries with semantic ranker in Azure AI Search (Preview)

Note

This feature is currently in public preview. This preview is provided without a service-level agreement, and is not recommended for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.

Query rewriting is the process of transforming a user's query into a more effective one, adding more terms and refining search results. The search service sends the search query (or a variation of it) to a generative model that generates alternative queries.

Query rewriting improves results from semantic ranking by correcting typos or spelling errors in user queries, and expanding queries with synonyms.

Search with query rewriting works like this:

  • The user query is sent via the search property in the request.
  • The search service sends the search query (or a variation of it) to a generative model that generates alternative queries.
  • The search service uses the original query and the rewritten queries to retrieve search results.

Query rewriting is an optional feature. Without query rewriting, the search service just uses the original query to retrieve search results.

Note

The rewritten queries might not contain all of the exact terms the original query had. This might impact search results if the query was highly specific and required exact matches for unique identifiers or product codes.

Prerequisites

  • A search service, Basic tier or higher.

Note

Query rewriting is currently available in the North Europe, and Southeast Asia regions.

Important

Semantic ranker is currently required for query rewriting.

  • An existing search index with a semantic configuration and rich text content. The examples in this guide use the hotels-sample-index sample data to demonstrate query rewriting. You can use your own data and index to test query rewriting.

  • You need a web client that supports REST API requests. The examples in this guide were tested with Visual Studio Code with the REST Client extension.

Tip

Content that includes explanations or definitions work best for semantic ranking.

Make a search request with query rewrites

In this REST API example, we use Search Documents to formulate the request. For more information about the request and response properties, see the API reference documentation.

  1. Paste the following request into a web client as a template.

    POST https://[search-service-name].search.windows.net/indexes/hotels-sample-index/docs/search?api-version=2024-11-01-preview
    {
        "search": "newer hotel near the water with a great restaurant",
        "semanticConfiguration":"en-semantic-config",
        "queryType":"semantic",
        "queryRewrites":"generative|count-5",
        "queryLanguage":"en-US",
        "debug":"queryRewrites",
        "top": 1
    }
    
    • You replace search-service-name with your search service name.

    • You replace hotels-sample-index with your index name if it's different.

    • We set "search" to a full text search query. The search property is required for query rewriting, unless you specify vector queries. If you specify vector queries, then the "search" text must match the "text" property of the "vectorQueries" object. Your search string can support either the simple syntax or full Lucene syntax.

    • We set "semanticConfiguration" to a predefined semantic configuration embedded in your index.

    • We set "queryType" to "semantic". We either need to set "queryType" to "semantic" or include a nonempty "semanticQuery" property in the request. Semantic ranking is required for query rewriting.

    • We set "queryRewrites" to "generative|count-5" to get up to five query rewrites. You can set the count to any value between 1 and 10.

    • Since we requested query rewrites by setting the "queryRewrites" property, we must set "queryLanguage" to the search text language. The Search service uses the same language for the query rewrites. In this example, we use "en-US". The supported locales are: en-AU, en-CA, en-GB, en-IN, en-US, ar-EG, ar-JO, ar-KW, ar-MA, ar-SA, bg-BG, bn-IN, ca-ES, cs-CZ, da-DK, de-DE, el-GR, es-ES, es-MX, et-EE, eu-ES, fa-AE, fi-FI, fr-CA, fr-FR, ga-IE, gl-ES, gu-IN, he-IL, hi-IN, hr-BA, hr-HR, hu-HU, hy-AM, id-ID, is-IS, it-IT, ja-JP, kn-IN, ko-KR, lt-LT, lv-LV, ml-IN, mr-IN, ms-BN, ms-MY, nb-NO, nl-BE, nl-NL, no-NO, pa-IN, pl-PL, pt-BR, pt-PT, ro-RO, ru-RU, sk-SK, sl-SL, sr-BA, sr-ME, sr-RS, sv-SE, ta-IN, te-IN, th-TH, tr-TR, uk-UA, ur-PK, vi-VN, zh-CN, zh-TW.

    • We set "debug" to "queryRewrites" to get the query rewrites in the response.

      Tip

      Only set "debug": "queryRewrites" for testing purposes. For better performance, don't use debug in production.

    • We set "top" to 1 to return only the top search result.

  2. Send the request to execute the query and return results.

Next, we evaluate the search results with the query rewrites.

Evaluate the response

Here's an example of a response that includes query rewrites:

"@search.debug": {
  "semantic": null,
  "queryRewrites": {
    "text": {
      "inputQuery": "newer hotel near the water with a great restaurant",
      "rewrites": [
        "new waterfront hotels with top-rated eateries",
        "new waterfront hotels with top-rated restaurants",
        "new waterfront hotels with excellent dining",
        "new waterfront hotels with top-rated dining",
        "new water-side hotels with top-rated restaurants"
      ]
    },
    "vectors": []
  }
},
"value": [
  {
    "@search.score": 58.992092,
    "@search.rerankerScore": 2.815633535385132,
    "HotelId": "18",
    "HotelName": "Ocean Water Resort & Spa",
    "Description": "New Luxury Hotel for the vacation of a lifetime. Bay views from every room, location near the pier, rooftop pool, waterfront dining & more.",
    "Description_fr": "Nouvel h\u00f4tel de luxe pour des vacances inoubliables. Vue sur la baie depuis chaque chambre, emplacement pr\u00e8s de la jet\u00e9e, piscine sur le toit, restaurant au bord de l'eau et plus encore.",
    "Category": "Luxury",
    "Tags": [
      "view",
      "pool",
      "restaurant"
    ],
    "ParkingIncluded": true,
    "LastRenovationDate": "2020-11-14T00:00:00Z",
    "Rating": 4.2,
    "Location": {
      "type": "Point",
      "coordinates": [
        -82.537735,
        27.943701
      ],
      "crs": {
        "type": "name",
        "properties": {
          "name": "EPSG:4326"
        }
      }
    },
    //... more properties redacted for brevity
  }
]

Here are some key points to note:

  • Because we set the "debug" property to "queryRewrites" for testing, the response includes a @search.debug object with the text input query and query rewrites.
  • Because we set the "queryRewrites" property to "generative|count-5", the response includes up to five query rewrites.
  • The "inputQuery" value is the query sent to the generative model for query rewriting. The input query isn't always the same as the user's "search" query.

Here's an example of a response without query rewrites.

"@search.debug": {
  "semantic": null,
  "queryRewrites": {
    "text": {
      "inputQuery": "",
      "rewrites": []
    },
    "vectors": []
  }
},
"value": [
  {
    "@search.score": 7.774868,
    "@search.rerankerScore": 2.815633535385132,
    "HotelId": "18",
    "HotelName": "Ocean Water Resort & Spa",
    "Description": "New Luxury Hotel for the vacation of a lifetime. Bay views from every room, location near the pier, rooftop pool, waterfront dining & more.",
    "Description_fr": "Nouvel h\u00f4tel de luxe pour des vacances inoubliables. Vue sur la baie depuis chaque chambre, emplacement pr\u00e8s de la jet\u00e9e, piscine sur le toit, restaurant au bord de l'eau et plus encore.",
    "Category": "Luxury",
    "Tags": [
      "view",
      "pool",
      "restaurant"
    ],
    "ParkingIncluded": true,
    "LastRenovationDate": "2020-11-14T00:00:00Z",
    "Rating": 4.2,
    "Location": {
      "type": "Point",
      "coordinates": [
        -82.537735,
        27.943701
      ],
      "crs": {
        "type": "name",
        "properties": {
          "name": "EPSG:4326"
        }
      }
    },
    //... more properties redacted for brevity
  }
]

Vector queries with query rewrite

You can include vector queries in your search request to combine keyword search and vector search into a single request and a unified response.

Here's an example of a query that includes a vector query with query rewrites. We modify a previous example to include a vector query.

  • We add a "vectorQueries" object to the request. This object includes a vector query with the "kind" set to "text".
  • The "text" value is the same as the "search" value. These values must be identical for query rewriting to work.
POST https://[search-service-name].search.windows.net/indexes/hotels-sample-index/docs/search?api-version=2024-11-01-preview
{
    "search": "newer hotel near the water with a great restaurant",
    "vectorQueries": [
        {
            "kind": "text",
            "text": "newer hotel near the water with a great restaurant",
            "k": 50,
            "fields": "Description",
            "queryRewrites": "generative|count-3"
        }
    ],
    "semanticConfiguration":"en-semantic-config",
    "queryType":"semantic",
    "queryRewrites":"generative|count-5",
    "queryLanguage":"en-US",
    "top": 1
}

The response includes query rewrites for both the text query and the vector query.

Test query rewrites with debug

You should test your query rewrites to ensure that they're working as expected. Set the "debug": "queryRewrites" property in your query request to get the query rewrites in the response. Setting "debug" is optional for testing purposes. For better performance, don't set this property in production.

Partial response reasons

You might observe that the debug (test) response includes an empty array for the text.rewrites and vectors properties.

{
  "@odata.context": "https://demo-search-svc.search.windows.net/indexes('hotels-sample-index')/$metadata#docs(*)",
  "@search.debug": {
    "semantic": null,
    "queryRewrites": {
      "text": {
        "rewrites": []
      },
      "vectors": []
    }
  },
  "@search.semanticPartialResponseReason": "Transient",
  "@search.semanticQueryRewriteResultType": "OriginalQueryOnly",
  //... more properties redacted for brevity
}

In the preceding example:

  • The response includes a @search.semanticPartialResponseReason property with a value of "Transient". This message means that at least one of the queries failed to complete.
  • The response also includes a @search.semanticQueryRewriteResultType property with a value of "OriginalQueryOnly". This message means that the query rewrites are unavailable. Only the original query is used to retrieve search results.

Next steps

Semantic ranking can be used in hybrid queries that combine keyword search and vector search into a single request and a unified response.