你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 Azure AI 搜索中创建混合查询

混合搜索将文本(关键字)和矢量查询结合在单个搜索请求中。 这两个查询并行执行。 结果按新的搜索分数进行合并和重新排序,使用倒数排名融合 (RRF) 返回一个统一的结果集。 在许多情况下,根据基准测试,语义排名的混合查询返回最相关的结果。

在本文中,将学习以下内容:

  • 设置基本混合请求
  • 添加参数和筛选器
  • 使用语义排名或矢量权重提高相关性
  • 通过控制输入优化查询行为 (maxTextRecallSize

先决条件

选择 API 或工具

  • Azure 门户中的搜索资源管理器(支持稳定版和预览版 API 搜索语法)有一个 JSON 视图,可让你将混合请求粘贴进去。

  • Azure SDK 的较新的稳定或预览包(请参阅 SDK 功能支持的更改日志)。

  • 如果您使用像 maxTextRecallSize 和 countAndFacetMode(预览版) 这样的预览功能,请使用 稳定的 REST API 或最近的预览 API 版本。

    为了方便阅读,我们使用 REST 示例来解释 API 的工作原理。 可以使用带 REST 扩展的 REST 客户端(例如 Visual Studio Code)来构建混合查询。 还可以使用 Azure SDK。 有关详细信息,请参阅 快速入门:矢量搜索

设置混合查询

本部分介绍混合查询的基本结构,以及如何在搜索资源管理器中设置一个查询或在 REST 客户端中执行。

结果均以纯文本形式返回,包括标记为 retrievable 的字段中的矢量。 由于数值矢量在搜索结果中不起作用,因此请选择索引中的其他字段作为矢量匹配的代理。 例如,如果索引具有“descriptionVector”和“descriptionText”字段,则查询可以匹配“descriptionVector”,但搜索结果可以显示“descriptionText”。 使用 select 参数仅指定结果中可人工读取的字段。

  1. 登录 Azure 门户并查找搜索服务。

  2. “搜索管理>索引”下,选择包含矢量和非矢量内容的索引。 搜索资源管理器 是第一个选项卡。

  3. “视图”下切换到 JSON 视图 ,以便可以粘贴向量查询。

  4. 将默认查询模板替换为混合查询。 基本混合查询具有指定的 search文本查询,以及指定的 vectorQueries.vector向量查询。 文本查询和矢量查询可以等价,也可以不等价,但通常具有相同的意向。

    此示例来自矢量快速入门,其中包含矢量和非矢量元素,以及多个查询示例。 为简洁起见,本文中截断了矢量。

    {
        "search": "historic hotel walk to restaurants and shopping",
        "vectorQueries": [
            {
                "vector": [0.01944167, 0.0040178085, -0.007816401 ... <remaining values omitted> ], 
                "k": 7,
                "fields": "DescriptionVector",
                "kind": "vector",
                "exhaustive": true
            }
        ]
    }
    
  5. 选择搜索

    提示

    如果隐藏矢量,搜索结果将更易读。 在“查询选项”中,启用“在搜索结果中隐藏矢量值”

  6. 下面是另一个版本的查询。 这一功能添加了用于记录找到的匹配项数量的 count,用于选择特定字段的 select 参数,以及用于返回前七个结果的 top 参数。

     {
         "count": true,
         "search": "historic hotel walk to restaurants and shopping",
         "select": "HotelId, HotelName, Category, Tags, Description",
         "top": 7,
         "vectorQueries": [
             {
                 "vector": [0.01944167, 0.0040178085, -0.007816401 ... <remaining values omitted> ], 
                 "k": 7,
                 "fields": "DescriptionVector",
                 "kind": "vector",
                 "exhaustive": true
             }
         ]
     }
    

设置 maxTextRecallSize 和 countAndFacetMode

注意

此功能目前处于公开预览状态。 此预览版未随附服务级别协议,建议不要用于生产工作负载。 某些功能可能不受支持或者受限。 有关详细信息,请参阅 Microsoft Azure 预览版补充使用条款

可以优化混合查询,以控制每个子查询对合并结果的贡献量。 设置 maxTextRecallSize 指定将多少个 BM25 排名结果传递给混合排名模型。

如果使用 maxTextRecallSize,可能还需要设置 CountAndFacetMode。 此参数用于确定countfacets是否应包括匹配搜索查询的所有文档,或仅包括在maxTextRecallSize窗口中检索到的文档。 默认值为“countAllResults”。

建议使用最新的预览版 REST API 来设置这些选项。

提示

混合查询优化的另一种方法是 矢量权重,用于增加请求中矢量查询的重要性。

  1. 使用 搜索 - POST(预览版)搜索 - GET (预览版) 指定预览参数。

  2. 添加 hybridSearch 查询参数对象,设置通过混合查询的 BM25 排名结果重新调用的最大文档数。 它具有两个属性:

    • maxTextRecallSize 指定向混合查询中使用的倒数排序融合 (RRF) 排名程序提供的 BM25 排序结果的数量。 默认值为 1,000。 最大值为 10,000。

    • countAndFacetMode 报告 BM25 排名结果的计数(如果使用的是分面)。 默认值为与查询匹配的所有文档。 (可选)可以将“count”限定为 maxTextRecallSize

  3. 设置 maxTextRecallSize

    • 如果矢量相似性搜索通常优于混合查询的文本端,则减少 maxTextRecallSize

    • 如果索引较大,并且默认值未捕获足够多的结果,则增加 maxTextRecallSize 。 使用更大的 BM25 排名结果集,还可以设置 topskipnext 来检索这些结果的部分。

以下 REST 示例显示了设置 maxTextRecallSize 的两个用例。

第一个示例将 maxTextRecallSize 减少到 100,将混合查询的文本端限制为仅 100 个文档。 它还将 countAndFacetMode 设置为仅包含来自 maxTextRecallSize 的结果。

POST https://[service-name].search.windows.net/indexes/[index-name]/docs/search?api-version=2024-05-01-Preview 

    { 
      "vectorQueries": [ 
        { 
          "kind": "vector", 
          "vector": [1.0, 2.0, 3.0], 
          "fields": "my_vector_field", 
          "k": 10 
        } 
      ], 
      "search": "hello world", 
      "hybridSearch": { 
        "maxTextRecallSize": 100, 
        "countAndFacetMode": "countRetrievableResults" 
      } 
    } 

第二个示例将 maxTextRecallSize 提高到 5,000。 它还使用 top、skip 和 next 从大型结果集中拉取结果。 在这种情况下,请求将从位置 1,500 到 2,000 开始的 BM25 排名结果作为文本查询对 RRF 复合结果集的贡献。

POST https://[service-name].search.windows.net/indexes/[index-name]/docs/search?api-version=2024-05-01-Preview 

    { 
      "vectorQueries": [ 
        { 
          "kind": "vector", 
          "vector": [1.0, 2.0, 3.0], 
          "fields": "my_vector_field", 
          "k": 10 
        } 
      ], 
      "search": "hello world",
      "top": 500,
      "skip": 1500,
      "next": 500,
      "hybridSearch": { 
        "maxTextRecallSize": 5000, 
        "countAndFacetMode": "countRetrievableResults" 
      } 
    } 

混合查询的示例

本部分包含多个演示混合查询模式的查询示例。

示例:使用筛选器进行混合搜索

此示例添加了一个筛选器,该筛选器应用于搜索索引的 filterable 非矢量字段。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2025-09-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "k": 10
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "vectorFilterMode": "preFilter",
    "filter": "ParkingIncluded",
    "top": "10"
}

要点

  • 筛选器应用于可筛选字段的内容。 在此示例中,ParkingIncluded 字段是一个布尔值,标记为索引架构中的 filterable

  • 在混合查询中,可以在查询执行之前应用筛选器以减少查询图面,也可以在查询执行之后应用筛选器来剪裁结果。 "preFilter" 是默认值。 若要使用 postFilterstrictPostFilter(预览版),请设置筛选器处理模式,如本示例所示。

  • 在筛选后查询结果时,结果数可能小于 top-n。

示例:使用筛选器定向矢量子查询的混合搜索(预览版)

使用最新的预览版 REST API,可以通过应用仅针对混合请求中的矢量子查询的辅助筛选器来替代搜索请求中的全局筛选器。

此功能通过确保筛选器仅影响矢量搜索结果而使基于关键字的搜索结果不受影响,提供精细的控制。

目标筛选器会完全替代全局筛选器(包括用于安全修整或地理空间搜索的任何筛选器)。 在需要全局筛选器的情况下(例如进行安全修整时),必须在顶级筛选器和每个矢量级筛选器中显式包含这些筛选器,以确保一致地强制执行安全性和其他约束。

要应用定向矢量过滤器:

下面是添加筛选器替代的混合查询的示例。 全局筛选器“Rating gt 3”在运行时被 filterOverride替换。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2025-08-01-preview

{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "exhaustive": true,
            "filterOverride": "Address/City eq 'Seattle'",
            "k": 10
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "select": "HotelName, Description, Address/City, Rating",
    "filter": "Rating gt 3"
    "debug": "vector",
    "top": 10
}

假设 你有语义排名器和 索引定义包括 语义配置,则可以构建包含矢量搜索和关键字搜索的查询,并在合并的结果集上具有语义排名。 (可选)可以添加字幕和答案。

对矢量使用语义排名时,请确保 k 设置为 50。 语义排序器最多使用 50 个匹配项作为输入。 如果指定小于 50 个匹配项,语义排名模型会失去必要的输入。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2025-09-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "k": 50
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "select": "HotelName, Description, Tags",
    "queryType": "semantic",
    "semanticConfiguration": "my-semantic-config",
    "captions": "extractive",
    "answers": "extractive",
    "top": "50"
}

要点

  • 语义排序器接受来自合并响应的最多 50 个结果。

  • “queryType”和“semanticConfiguration”是必需的。

  • “captions”和“answers”是可选的。 从结果的逐字文本中提取值。 仅当结果包含的内容具有查询答案的特征时,才会返回答案。

示例:使用筛选器进行语义混合搜索

下面是集合中的最后一个查询。 它是与上一示例相同的语义混合查询,但带有筛选器。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2025-09-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "vectorQueries": [
        {
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "fields": "DescriptionVector",
            "kind": "vector",
            "k": 50
        }
    ],
    "search": "historic hotel walk to restaurants and shopping",
    "select": "HotelName, Description, Tags",
    "queryType": "semantic",
    "semanticConfiguration": "my-semantic-config",
    "captions": "extractive",
    "answers": "extractive",
    "filter": "ParkingIsIncluded'",
    "vectorFilterMode": "preFilter",
    "top": "50"
}

要点

  • 筛选器模式可能会影响语义重排器可用的结果数。 最佳做法是,向语义排名器提供最大数目的文档 (50)。 如果预筛选器或后筛选器过于挑剔,给语义排名器提供的文档少于50个时,可能无法充分发挥其作用。

  • preFilter 在查询执行之前应用。 如果预筛选器将搜索区域减少到 100 个文档,则矢量查询将针对这 100 个文档的 DescriptionVector 字段执行,返回 k=50 个最佳匹配项。 然后,这 50 个匹配的文档将传递给 RRF 以获取合并结果,然后再传递给语义排名器。

  • postFilter 在查询执行后应用。 如果 k=50 在向量查询端返回 50 个匹配项,然后向 50 个匹配项应用筛选器,得到的结果数将减少到满足筛选条件的文档数。 最终需要传递给语义排序器的文档少于 50 个。 如果要使用语义排序器,请记住这一点。 语义排序器在输入文档数为 50 个时效果最佳。

  • strictPostFilter(预览版)在查询执行后对未筛选的前 k 个结果应用。 它始终返回小于或等于 k 个文档。 如果未筛选的 k=50 返回 50 个未筛选的结果,并且筛选器与 30 个文档匹配,则即使索引包含超过 30 个与筛选器匹配的文档,结果集中也仅返回 30 个文档。 由于此模式极大地减少了召回率,因此不建议将其用于语义排名器。

配置查询响应

设置混合查询时,请考虑响应结构。 搜索引擎对匹配的文档进行排名,并返回相关度最高的结果。 响应是平展行集。 查询中的参数确定每行中有哪些字段以及响应中有多少行。

响应中的字段

搜索结果由搜索索引中的retrievable 字段组成。 结果可以是:

  • 所有 retrievable 字段(REST API 默认值)。
  • 在查询参数 select 中显式列出的字段。

本文中的示例使用了一个 select 语句来指定响应中的文本(非函数)字段。

注意

不会对矢量执行反向工程使其成为人类可读的文本,因此要避免在响应中将其返回。 相反,选择代表搜索文档的非矢量字段。 例如,如果查询以“DescriptionVector”字段为目标,则在响应中有一个(“Description”)时返回等效的文本字段。

结果数

查询可能与任意数量的文档匹配,如果搜索条件较弱(例如“search=*”用于 null 查询),则会尽可能匹配所有文档。 由于很少有实际返回无限制的结果的情况,因此应为整体响应指定最大值

  • 对于仅关键字查询(无向量),为 "top": n 个结果
  • 仅矢量查询的 "k": n 结果
  • 对于包含“search”参数的混合查询,为 "top": n 个结果(具有或不具有语义)

ktop 都是可选的。 如果未指定,响应中的默认结果数为 50。 可以设置 topskip逐页浏览更多结果或更改默认值。

注意

如果在 2024-05-01-preview API 中使用混合搜索,可以使用 maxTextRecallSize 控制关键字查询的结果数。 将其与一个 k 设置组合使用,可控制每个搜索子系统中的表示形式(关键字和矢量)。

语义排序器结果

注意

语义排序器最多可接受 50 个结果。

如果在 2024-05-01-preview 或更高版本中使用语义排序器,最佳做法是设置 kmaxTextRecallSize 使其总和至少达到 50。 然后,可以使用 top 参数限制返回给用户的结果。

如果在以前的 API 中使用语义排序器,请按以下操作:

  • 对于仅关键字搜索(无向量)设置为 top 50
  • 对于设置为 k 50 的混合搜索,请确保语义排名器至少获得 50 个结果。

排名

为混合查询创建多个集,包含或不包含可选的语义排名。 结果排名由倒数排名融合 (RRF) 计算得出。

在本部分中,比较单矢量搜索和简单混合搜索之间的响应,来获得排名靠前的结果。 不同的排名算法、HNSW 的相似性指标和 RRF 就是这种情况,会产生具有不同量级的分数。 此行为是设计使然。 即使存在很高的相似性匹配,RRF 分数也可能看起来很低。 较低的分数是 RRF 算法的一个特征。 在使用 RRF 的混合搜索中,考虑到已通过 RRF 排名的文档的分数相对较小(这与纯矢量搜索相反),结果中会包含已排名文档的更多倒数。

单一向量搜索:结果按余弦相似性排序(默认的向量相似性距离函数)。@search.score

{
    "@search.score": 0.8399121,
    "HotelId": "49",
    "HotelName": "Swirling Currents Hotel",
    "Description": "Spacious rooms, glamorous suites and residences, rooftop pool, walking access to shopping, dining, entertainment and the city center.",
    "Category": "Luxury",
    "Address": {
    "City": "Arlington"
    }
}

混合搜索:使用倒数排名融合进行排名的混合结果的 @search.score。

{
    "@search.score": 0.032786883413791656,
    "HotelId": "49",
    "HotelName": "Swirling Currents Hotel",
    "Description": "Spacious rooms, glamorous suites and residences, rooftop pool, walking access to shopping, dining, entertainment and the city center.",
    "Category": "Luxury",
    "Address": {
    "City": "Arlington"
    }
}

后续步骤

建议查看 PythonC#JavaScript 的矢量演示代码。