教程:为一个搜索索引配置多个 Blob 索引器

注释

Azure AI 搜索可通过Azure门户、REST API 和Azure SDK获取。

Important

标记为“预览”的特性、功能或属性不受服务级别协议 (SLA) 保障,不建议用于生产工作负载,并且在正式发布之前可能会更改或受到限制。 Azure AI 搜索预览条款适用于所有预览功能,无论是独立功能还是正式版功能的一部分。

在本教程中,为写入一个Azure AI 搜索索引的 DOCX、JSON 和 CSV 内容配置独立的 blob 索引器。 可空联合架构使每个管道都能填充其负责的字段,同时让应用程序能够统一查询所有格式。 当索引器具有兼容的字段映射并面向同一索引时,可以将此模式扩展到其他兼容的索引器类型。 本教程仅演示并验证文件夹范围的 Blob 索引器。

在本教程中,你将了解:

  • 在单独的 Blob 文件夹中准备 DOCX、JSON 和 CSV 示例数据
  • 创建联合架构索引和三个文件夹范围的 Blob 数据源
  • 使用不同的分析和扩充路径配置三个索引器
  • 运行索引器并验证组合关键字、矢量和混合结果
  • 查看内容所有权、故障排除和清理做法

Azure内容理解技能中的语义分块(预览版)需要 2026-08-01-preview REST API。 没有语义分块的多索引器模式、索引投影和内容理解技能已正式发布。 但是,为了保持一致性,本教程在所有请求中使用 2026-08-01-preview 。

先决条件

  • 一份 Azure 订阅。 免费创建一个。

  • 具有系统分配的托管标识的Azure AI 搜索服务。 在“搜索服务设置密钥>页上,将 API 访问控制设置为“两者”,以便服务接受Microsoft Entra ID持有者令牌或 API 密钥。 此设置可在本教程中启用持有者令牌请求,而无需中断使用 API 密钥的现有客户端。 仅当不再需要基于密钥的身份验证时,才选择基于 角色的访问控制 。 有关详细信息,请参阅 “启用基于角色的访问控制”。

  • 用户帐户必须在搜索服务上具有 搜索服务参与者、 搜索索引数据参与者和 搜索索引数据读取者 角色。 这些角色授权在整个教程中使用持有者令牌发送的管理和查询操作。 有关详细信息,请参阅 通过角色连接到 Azure AI 搜索。 如果请求同时包含持有者令牌和 API 密钥,则 API 密钥优先。

  • 具有 Blob 容器 的 Azure 存储帐户。 在容器中创建 docx、json 和 csv 文件夹。 将存储帐户范围内的 存储 Blob 数据读取者 角色分配给搜索服务的托管标识。 你的用户帐户需要在存储帐户范围内具有 Storage Blob Data Contributor 角色,才能上传示例文件。

  • Azure CLI和可以发送经过身份验证的请求的 REST 客户端。 运行 az login,选择包含你的搜索服务的订阅,并为 Azure AI 搜索作用域请求获取 Bearer 令牌:

    az account get-access-token --scope https://search.azure.cn/.default --query accessToken --output tsv
    

    将返回的令牌复制到本教程中每个 Authorization: Bearer <search-access-token> 标头使用的 <search-access-token> 占位符内。 访问令牌过期,因此,如果收到身份验证错误,请请求另一个令牌。 在发送请求之前,请替换所有其他 尖括号占位符 。

占位符引用

本教程使用以下占位符:

占位符 Value
<search-endpoint> https://<search-service-name>.search.azure.cn
<search-access-token> Azure CLI 返回的 Azure AI 搜索 访问令牌
<storage-resource-id> /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Storage/storageAccounts/<storage-account-name>
<container-name> 你的 blob 容器的名称
<storage-account-name> 你的存储帐户名称

查看体系结构

三个 blob 索引器单独写入同一索引。 当多个索引器具有兼容的字段映射并面向同一索引时,可以应用常规设计,但本教程演示并仅验证文件夹范围的 Blob 索引器。

sourceType不是 Azure AI 搜索 的系统字段。 这是一个由文章定义的鉴别器,JSON 和 CSV 源记录会直接填充该字段,而 DOCX 技能集会在扩充过程中添加该字段。 Azure AI 搜索不推断哪个索引器编写了文档。

管道 源形状 索引路径 矢量行为
DOCX 一个较短的 .docx 文件 内容理解语义分块(预览)、常量 sourceType 分配、嵌入技能以及索引投影 已填充
JSON JSON 数组中的两个对象 直接字段映射 有意设为 null
CSV 带有第一行标题的两行 直接字段映射和嵌入技能 已填充

如果示例 DOCX 生成一个区块,则示例结果包含五个搜索文档:一个 DOCX 投影子文档、两个 JSON 产品和两个 CSV 票证。 这四个直接索引的文档(2 JSON + 2 CSV)从源数据获取密钥。 DOCX 子项从索引投影中获得生成的键。 较长或结构更复杂的文档可能会生成多个投影子项。

Warning

为每个直接建立索引的源赋予全局唯一的文档键值,例如以 json_ 和 csv_ 为前缀的值。 索引器使用文档更新语义:当两个写入操作具有相同的键时,可以合并或覆盖字段。 冲突可能会导致生成一个存在不安全混合所有权的文档。

共享索引包含以下字段:

  • id、parentId、sourceType、content、contentVector、sourceUri、title 和 lastModified。
  • 可为空的格式特定字段:category、price、status 和 priority。

该 id 字段是索引键字段。 其 keyword 分析器将每个标识符保留为一个确切值。 JSON 和 CSV 记录提供唯一的文档键,而索引投影则生成 DOCX 子键。 当源内容或投影区块边界发生更改时,生成的子密钥可能会更改,因此不要预测或保留有关其值的假设。

准备示例文件

每个索引器从其关联的文件夹中读取一种格式。 为每个文件夹创建一个小文件,以便每个管道都有可供建立索引的内容,并能在本教程后续部分从共享索引中进行查询。

准备示例文件:

  1. 在 docx 文件夹中,上传一个名为 search-overview.docx 的小文件。 添加标题 Search overview 和此一句段落: Azure AI 搜索 supports keyword and vector search over indexed content. 短文档通常生成一个语义区块,但区块计数取决于文档结构。

  2. 在 json 文件夹中,使用此双元素数组上传 products.json :

    [
      {
        "id": "json_product_001",
        "sourceType": "json",
        "content": "Compact wireless keyboard for shared workspaces.",
        "sourceUri": "https://<storage-account-name>.blob.core.chinacloudapi.cn/<container-name>/json/products.json#product-001",
        "title": "Compact wireless keyboard",
        "lastModified": "2026-08-07T00:00:00Z",
        "category": "Accessories",
        "price": 49.99
      },
      {
        "id": "json_product_002",
        "sourceType": "json",
        "content": "Adjustable monitor stand with cable management.",
        "sourceUri": "https://<storage-account-name>.blob.core.chinacloudapi.cn/<container-name>/json/products.json#product-002",
        "title": "Adjustable monitor stand",
        "lastModified": "2026-08-07T00:00:00Z",
        "category": "Office",
        "price": 89.50
      }
    ]
    
  3. 在 csv 文件夹中,使用以下两行上传 tickets.csv :

    id,sourceType,content,sourceUri,title,lastModified,status,priority
    csv_ticket_001,csv,"Search results omit a recently added product.","https://<storage-account-name>.blob.core.chinacloudapi.cn/<container-name>/csv/tickets.csv#ticket-001","Missing product",2026-08-07T00:00:00Z,open,high
    csv_ticket_002,csv,"A synonym rule needs review before deployment.","https://<storage-account-name>.blob.core.chinacloudapi.cn/<container-name>/csv/tickets.csv#ticket-002","Review synonym rule",2026-08-07T00:00:00Z,pending,medium
    

    前缀 json_ 和 csv_ 使直接索引的文档键值在两个管道之间保持唯一。

  4. 验证容器中是否存在所有三个 Blob:

    az storage blob list \
      --account-name <storage-account-name> \
      --container-name <container-name> \
      --auth-mode login \
      --query "[].name" \
      --output tsv
    

    Reference:az storage blob list (Azure CLI)

    预期输出:

    csv/tickets.csv
    docx/search-overview.docx
    json/products.json
    

    如果输出未列出所有三个文件,请验证是否已将每个文件上传到正确的文件夹路径。

创建联合架构索引

创建一个接受所有三个文档形状的索引。 管道未填充的字段保留为 null。 矢量化器在查询时将查询文本转换为向量,而这两个技能组都使用相同的嵌入模型来生成索引时的向量。

若要创建联合架构索引,请执行以下命令:

  1. 发送创建请求:

    POST <search-endpoint>/indexes?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "multi-source-index",
      "fields": [
        {
          "name": "id",
          "type": "Edm.String",
          "key": true,
          "searchable": true,
          "filterable": true,
          "retrievable": true,
          "analyzer": "keyword"
        },
        {
          "name": "parentId",
          "type": "Edm.String",
          "filterable": true,
          "retrievable": true
        },
        {
          "name": "sourceType",
          "type": "Edm.String",
          "filterable": true,
          "facetable": true,
          "retrievable": true
        },
        {
          "name": "content",
          "type": "Edm.String",
          "searchable": true,
          "retrievable": true
        },
        {
          "name": "contentVector",
          "type": "Collection(Edm.Single)",
          "searchable": true,
          "retrievable": false,
          "stored": false,
          "dimensions": 1536,
          "vectorSearchProfile": "content-vector-profile"
        },
        {
          "name": "sourceUri",
          "type": "Edm.String",
          "filterable": true,
          "retrievable": true
        },
        {
          "name": "title",
          "type": "Edm.String",
          "searchable": true,
          "retrievable": true
        },
        {
          "name": "lastModified",
          "type": "Edm.DateTimeOffset",
          "filterable": true,
          "sortable": true,
          "retrievable": true
        },
        {
          "name": "category",
          "type": "Edm.String",
          "filterable": true,
          "facetable": true,
          "retrievable": true
        },
        {
          "name": "price",
          "type": "Edm.Double",
          "filterable": true,
          "sortable": true,
          "retrievable": true
        },
        {
          "name": "status",
          "type": "Edm.String",
          "filterable": true,
          "facetable": true,
          "retrievable": true
        },
        {
          "name": "priority",
          "type": "Edm.String",
          "filterable": true,
          "facetable": true,
          "retrievable": true
        }
      ],
      "vectorSearch": {
        "algorithms": [
          {
            "name": "content-hnsw",
            "kind": "hnsw",
            "hnswParameters": {
              "metric": "cosine",
              "m": 4,
              "efConstruction": 400,
              "efSearch": 500
            }
          }
        ],
        "profiles": [
          {
            "name": "content-vector-profile",
            "algorithm": "content-hnsw",
            "vectorizer": "content-azure-openai-vectorizer"
          }
        ],
        "vectorizers": [
          {
            "name": "content-azure-openai-vectorizer",
            "kind": "azureOpenAI",
            "azureOpenAIParameters": {
              "resourceUri": "<resource-endpoint>",
              "deploymentId": "<embedding-deployment-name>",
              "modelName": "text-embedding-3-small"
            }
          }
        ]
      }
    }
    

    Reference:Create Index (REST API)

    响应返回具有完整索引定义的 HTTP 201 Created 。

  2. 验证是否已创建索引:

    GET <search-endpoint>/indexes/multi-source-index?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    Reference:Get Index (REST API)

    响应包含 "name": "multi-source-index" 和 12 个字段。 确认 fields 数组长度等于 12,并且 vectorSearch 部分包含 content-azure-openai-vectorizer。

创建三个文件夹范围的数据源

为每个 Blob 文件夹创建单独的数据源。 这三个定义都可以使用相同的存储连接和容器。 该值 container.query 将每个数据源限制为一个虚拟文件夹。 例如, "query": "docx" 将 DOCX 数据源限制为文件夹下的 docx Blob。

每个索引器还将 indexedFileNameExtensions 用作文件类型允许列表。 文件夹查询和扩展允许列表是独立的筛选器:数据源限制索引器枚举的文件夹,以及索引器配置限制该文件夹中的文件类型符合条件。 此示例不需要 excludedFileNameExtensions ,因为每个允许列表只包含一个扩展。

要创建这三个文件夹作用域的数据源:

  1. 创建 DOCX 数据源:

    POST <search-endpoint>/datasources?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "docx-blob-datasource",
      "type": "azureblob",
      "credentials": {
        "connectionString": "ResourceId=<storage-resource-id>;"
      },
      "container": {
        "name": "<container-name>",
        "query": "docx"
      }
    }
    

    参考:创建数据源(REST API)

    响应返回 HTTP 201 Created。

  2. 创建 JSON 数据源:

    POST <search-endpoint>/datasources?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "json-blob-datasource",
      "type": "azureblob",
      "credentials": {
        "connectionString": "ResourceId=<storage-resource-id>;"
      },
      "container": {
        "name": "<container-name>",
        "query": "json"
      }
    }
    

    参考:创建数据源(REST API)

    响应返回 HTTP 201 Created。

  3. 创建 CSV 数据源:

    POST <search-endpoint>/datasources?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "csv-blob-datasource",
      "type": "azureblob",
      "credentials": {
        "connectionString": "ResourceId=<storage-resource-id>;"
      },
      "container": {
        "name": "<container-name>",
        "query": "csv"
      }
    }
    

    参考:创建数据源(REST API)

    响应返回 HTTP 201 Created。

验证所有三个数据源是否存在:

GET <search-endpoint>/datasources?api-version=2026-08-01-preview
Authorization: Bearer <search-access-token>

Reference:List Data Sources (REST API)

响应value数组包含docx-blob-datasource和 json-blob-datasourcecsv-blob-datasource。 如果缺少任何项目,请检查相应的创建步骤是否有误。

配置 DOCX 管道

DOCX 管道将技能集与索引器配对。 技能集使用语义分块(预览),分配 docx 判别器,为每个分块生成嵌入,并将每个子项投影到共享索引中。 索引器将该技能集绑定到 docx-blob-datasource,使用 allowSkillsetToReadFileData 读取文件,并对每个 blob 运行该技能集。

若要配置 DOCX 管道,请执行以下操作:

  1. 创建技能集:

    POST <search-endpoint>/skillsets?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "docx-semantic-skillset",
      "description": "Chunk and vectorize DOCX files for the shared index.",
      "skills": [
        {
          "@odata.type": "#Microsoft.Skills.Util.ContentUnderstandingSkill",
          "name": "docx-content-understanding",
          "context": "/document",
          "chunkingProperties": {
            "method": "semantic",
            "unit": "tokens",
            "maximumLength": 500
          },
          "inputs": [
            {
              "name": "file_data",
              "source": "/document/file_data"
            }
          ],
          "outputs": [
            {
              "name": "text_sections",
              "targetName": "text_sections"
            }
          ]
        },
        {
          "@odata.type": "#Microsoft.Skills.Util.ConditionalSkill",
          "name": "docx-source-type",
          "context": "/document/text_sections/*",
          "inputs": [
            {
              "name": "condition",
              "source": "= true"
            },
            {
              "name": "whenTrue",
              "source": "= 'docx'"
            },
            {
              "name": "whenFalse",
              "source": "= null"
            }
          ],
          "outputs": [
            {
              "name": "output",
              "targetName": "source_type"
            }
          ]
        }
      ],
    
      "indexProjections": {
        "selectors": [
          {
            "targetIndexName": "multi-source-index",
            "parentKeyFieldName": "parentId",
            "sourceContext": "/document/text_sections/*",
            "mappings": [
              {
                "name": "sourceType",
                "source": "/document/text_sections/*/source_type"
              },
              {
                "name": "content",
                "source": "/document/text_sections/*/content"
              },
              {
                "name": "contentVector",
                "source": "/document/text_sections/*/content_vector"
              },
              {
                "name": "sourceUri",
                "source": "/document/metadata_storage_path"
              },
              {
                "name": "title",
                "source": "/document/metadata_storage_name"
              },
              {
                "name": "lastModified",
                "source": "/document/metadata_storage_last_modified"
              }
            ]
          }
        ],
        "parameters": {
          "projectionMode": "skipIndexingParentDocuments"
        }
      }
    }
    

    参考:Azure 内容理解技能和定义索引投影

    响应返回 HTTP 201 Created。

    条件技能既不选择也不排除 Blob 对象。 文件选择在技能集运行之前就已经通过 container.query 和 indexedFileNameExtensions 完成了。 它的恒为 true 的条件仅在每个投影块上将常量值 docx 赋给 sourceType。

  2. 验证是否已创建技能集:

    GET <search-endpoint>/skillsets/docx-semantic-skillset?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:获取技能集 (REST API)

    响应包含 "name": "docx-semantic-skillset",以及 skills 数组中的三个技能。

  3. 创建 DOCX 索引器:

    POST <search-endpoint>/indexers?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "docx-indexer",
      "dataSourceName": "docx-blob-datasource",
      "targetIndexName": "multi-source-index",
      "skillsetName": "docx-semantic-skillset",
      "parameters": {
        "batchSize": 1,
        "configuration": {
          "dataToExtract": "contentAndMetadata",
          "parsingMode": "default",
          "indexedFileNameExtensions": ".docx",
          "allowSkillsetToReadFileData": true
        }
      },
      "fieldMappings": [],
      "outputFieldMappings": []
    }
    

    Reference:Create Indexer (REST API)

    响应返回 HTTP 201 Created。 索引器会自动启动其第一次运行。

    索引投影创建 id 和 parentId。 不要在投影选择器中映射任一字段。

  4. 检查索引器的状态:

    GET <search-endpoint>/indexers/docx-indexer/status?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:获取索引器状态 (REST API)

    等待lastResult.status显示success,并确认lastResult.itemsFailed为0。 如果状态显示 inProgress,请等待 30 秒,然后再次检查。 你将在本教程的后续内容中,通过查询索引来验证投影生成的 DOCX 输出。

配置 JSON 管道

JSON 管道单独使用索引器,而无需技能集。 索引器为每个数组元素创建一个搜索文档,直接映射源端拥有的键和其他字段,并有意将 contentVector 保留为 null。 矢量查询排除这些文档,而全文查询和筛选查询仍可返回它们。

配置 JSON 管道:

  1. 创建 JSON 索引器:

    POST <search-endpoint>/indexers?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "json-indexer",
      "dataSourceName": "json-blob-datasource",
      "targetIndexName": "multi-source-index",
      "parameters": {
        "configuration": {
          "parsingMode": "jsonArray",
          "indexedFileNameExtensions": ".json"
        }
      },
      "fieldMappings": [
        {
          "sourceFieldName": "/id",
          "targetFieldName": "id"
        },
        {
          "sourceFieldName": "/sourceType",
          "targetFieldName": "sourceType"
        },
        {
          "sourceFieldName": "/content",
          "targetFieldName": "content"
        },
        {
          "sourceFieldName": "/sourceUri",
          "targetFieldName": "sourceUri"
        },
        {
          "sourceFieldName": "/title",
          "targetFieldName": "title"
        },
        {
          "sourceFieldName": "/lastModified",
          "targetFieldName": "lastModified"
        },
        {
          "sourceFieldName": "/category",
          "targetFieldName": "category"
        },
        {
          "sourceFieldName": "/price",
          "targetFieldName": "price"
        }
      ],
      "outputFieldMappings": []
    }
    

    参考:创建索引器(REST API)、 索引 JSON Blob 和文件,以及 定义字段映射

    响应返回 HTTP 201 Created。 索引器会自动启动其第一次运行。

  2. 验证索引器是否处理了这两条记录:

    GET <search-endpoint>/indexers/json-indexer/status?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:获取索引器状态 (REST API)

    等待lastResult.status显示success,并确认lastResult.itemsFailed为0。 如果状态显示 inProgress,请等待 15 秒,然后再次检查。 您将在本教程稍后通过查询该索引来验证这两条 JSON 记录。

配置 CSV 管道

CSV 管道将技能集与索引器配对。 索引器为每一行创建一个搜索文档,直接映射源端键和其他字段,并将技能集的嵌入映射到 contentVector。 由于这些文档携带矢量,因此全文查询和矢量查询都可以返回它们。

配置 CSV 管道:

  1. 创建 CSV 技能集:

    POST <search-endpoint>/skillsets?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "csv-embedding-skillset",
      "description": "Vectorize CSV ticket content for the shared index.",
      "skills": [
        {
          "@odata.type": "#Microsoft.Skills.Text.AzureOpenAIEmbeddingSkill",
          "name": "csv-embedding",
          "context": "/document",
          "resourceUri": "<resource-endpoint>",
          "deploymentId": "<embedding-deployment-name>",
          "modelName": "text-embedding-3-small",
          "dimensions": 1536,
          "inputs": [
            {
              "name": "text",
              "source": "/document/content"
            }
          ],
          "outputs": [
            {
              "name": "embedding",
              "targetName": "csv_content_vector"
            }
          ]
        }
      ]
    }
    

    参考:创建技能集 (REST API)

    响应返回 HTTP 201 Created。

  2. 验证是否已创建技能集:

    GET <search-endpoint>/skillsets/csv-embedding-skillset?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:获取技能集 (REST API)

    响应包含 "name": "csv-embedding-skillset" 以及 skills 数组中的一个技能。

  3. 创建 CSV 索引器:

    POST <search-endpoint>/indexers?api-version=2026-08-01-preview
    Content-Type: application/json
    Authorization: Bearer <search-access-token>
    
    {
      "name": "csv-indexer",
      "dataSourceName": "csv-blob-datasource",
      "targetIndexName": "multi-source-index",
      "skillsetName": "csv-embedding-skillset",
      "parameters": {
        "configuration": {
          "parsingMode": "delimitedText",
          "firstLineContainsHeaders": true,
          "delimitedTextDelimiter": ",",
          "indexedFileNameExtensions": ".csv"
        }
      },
      "fieldMappings": [
        {
          "sourceFieldName": "id",
          "targetFieldName": "id"
        },
        {
          "sourceFieldName": "sourceType",
          "targetFieldName": "sourceType"
        },
        {
          "sourceFieldName": "content",
          "targetFieldName": "content"
        },
        {
          "sourceFieldName": "sourceUri",
          "targetFieldName": "sourceUri"
        },
        {
          "sourceFieldName": "title",
          "targetFieldName": "title"
        },
        {
          "sourceFieldName": "lastModified",
          "targetFieldName": "lastModified"
        },
        {
          "sourceFieldName": "status",
          "targetFieldName": "status"
        },
        {
          "sourceFieldName": "priority",
          "targetFieldName": "priority"
        }
      ],
      "outputFieldMappings": [
        {
          "sourceFieldName": "/document/csv_content_vector",
          "targetFieldName": "contentVector"
        }
      ]
    }
    

    参考:创建索引器(REST API)、 索引 CSV blob 和文件,以及 输出字段映射

    响应返回 HTTP 201 Created。 索引器会自动启动其第一次运行。

  4. 验证索引器是否处理了这两行:

    GET <search-endpoint>/indexers/csv-indexer/status?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:获取索引器状态 (REST API)

    等待lastResult.status显示success,并确认lastResult.itemsFailed为0。 如果状态显示 inProgress,请等待 15 秒,然后再次检查。 您将在本教程的后续部分通过查询索引来验证这两行 CSV 数据。

运行和监视索引器

创建索引器时,每个索引器都会自动启动其首次运行。 若要启动另一个运行并验证结果::

  1. 运行三个索引器:

    POST <search-endpoint>/indexers/docx-indexer/run?api-version=2026-08-01-preview
    Content-Type: application/json
    Content-Length: 0
    Authorization: Bearer <search-access-token>
    
    POST <search-endpoint>/indexers/json-indexer/run?api-version=2026-08-01-preview
    Content-Type: application/json
    Content-Length: 0
    Authorization: Bearer <search-access-token>
    
    POST <search-endpoint>/indexers/csv-indexer/run?api-version=2026-08-01-preview
    Content-Type: application/json
    Content-Length: 0
    Authorization: Bearer <search-access-token>
    

    Reference:Run Indexer (REST API)

    每个运行请求返回包含空正文的 HTTP 202 Accepted 。 某些 REST 客户端对于不含正文的请求需要 Content-Length: 0 标头。

    注释

    如果源数据自上次运行以来未更改,索引器可能会报告 itemsProcessed 为 0。 这种行为是预期现象,因为索引器使用变更检测,并跳过未修改的 Blob。

  2. 检查每个索引器的状态:

    GET <search-endpoint>/indexers/docx-indexer/status?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    
    GET <search-endpoint>/indexers/json-indexer/status?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    
    GET <search-endpoint>/indexers/csv-indexer/status?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:获取索引器状态 (REST API)

    对于每个索引器,请确认 lastResult.status 为 success,且 lastResult.itemsFailed 为 0。 服务会在 lastResult 中报告处理详情;请在下一部分验证索引文档计数,因为投影得到的分块和解析后的记录不一定与源 Blob 一一对应。

查询共享索引

使用以下请求验证合并的结果。

验证联合结果

返回由三个索引器编写的所有文档:

POST <search-endpoint>/indexes/multi-source-index/docs/search?api-version=2026-08-01-preview
Content-Type: application/json
Authorization: Bearer <search-access-token>

{
  "search": "*",
  "select": "id,parentId,sourceType,title",
  "count": true
}

参考:搜索文档(REST API)

结果包含两个 JSON 产品、两个 CSV 票证和一个或多个 DOCX 区块。 如果示例 DOCX 生成一个区块, @odata.count 则为 5. 确认所有三个 sourceType 值均出现:docx、json 和 csv。

按鉴别器查询

返回两个 JSON 产品:

POST <search-endpoint>/indexes/multi-source-index/docs/search?api-version=2026-08-01-preview
Content-Type: application/json
Authorization: Bearer <search-access-token>

{
  "search": "*",
  "filter": "sourceType eq 'json'",
  "select": "id,sourceType,title,category,price",
  "count": true
}

参考:搜索文档(REST API)

确认 @odata.count 为 2。 结果都具有 category 值和 price 值。 status和priority字段不在选择列表中,因为它们属于 CSV 架构。

运行全文查询

全文搜索会考虑所有具有匹配可搜索文本的文档,包括具有 null 向量的 JSON 记录。

POST <search-endpoint>/indexes/multi-source-index/docs/search?api-version=2026-08-01-preview
Content-Type: application/json
Authorization: Bearer <search-access-token>

{
  "search": "search product",
  "searchFields": "content,title",
  "select": "id,parentId,sourceType,title,content",
  "count": true
}

参考:搜索文档(REST API)

结果包括来自任何源类型的文档,这些文档的 content 或 title 字段中包含“search”或“product”。 使用示例数据时,应会匹配到 DOCX 分块(包含“search”)和 CSV 工单(包含“product”)中的内容。

运行矢量查询

将文本发送到索引向量器,而不是粘贴 1,536 向量值。 结果包含矢量化 DOCX 和 CSV 文档,而不是 NULL 的 contentVector JSON 文档。

POST <search-endpoint>/indexes/multi-source-index/docs/search?api-version=2026-08-01-preview
Content-Type: application/json
Authorization: Bearer <search-access-token>

{
  "vectorQueries": [
    {
      "kind": "text",
      "text": "search indexing issue",
      "fields": "contentVector",
      "k": 3
    }
  ],
  "select": "id,parentId,sourceType,title,content"
}

参考:搜索文档(REST API)

确认没有结果包含 "sourceType": "json"。 JSON 文档被排除,因为它们 contentVector 为 null。

运行筛选的矢量查询

将矢量结果限制为 CSV 票证:

POST <search-endpoint>/indexes/multi-source-index/docs/search?api-version=2026-08-01-preview
Content-Type: application/json
Authorization: Bearer <search-access-token>

{
  "filter": "sourceType eq 'csv'",
  "vectorFilterMode": "preFilter",
  "vectorQueries": [
    {
      "kind": "text",
      "text": "deployment review",
      "fields": "contentVector",
      "k": 2
    }
  ],
  "select": "id,sourceType,title,status,priority"
}

参考:搜索文档(REST API)

确认所有结果都具有 "sourceType": "csv" 并包含 status 和 priority 字段。

运行混合查询

在一个请求中合并关键字和矢量检索:

POST <search-endpoint>/indexes/multi-source-index/docs/search?api-version=2026-08-01-preview
Content-Type: application/json
Authorization: Bearer <search-access-token>

{
  "search": "search issue",
  "searchFields": "content,title",
  "vectorQueries": [
    {
      "kind": "text",
      "text": "search issue",
      "fields": "contentVector",
      "k": 3
    }
  ],
  "select": "id,parentId,sourceType,title,content"
}

参考:搜索文档(REST API)

混合查询将关键字匹配(可以包含 JSON 文档)与矢量匹配(不包括 null 向量文档)组合在一起。 当关键字和矢量词在管道之间匹配时,合并的结果集可以包含来自所有三种源类型的文档。

有关更多查询选项,请参阅 “创建矢量查询 ”和 “创建混合查询”。

管理和核对索引内容

将每个索引器视为独立编写器,并为其文档键值定义所有权和清理规则。

  • 单独监视、计划、运行和重置每个索引器。 某个管道发生故障,并不会删除另一个管道已经写入的文档。 例如,格式不正确的 CSV 可能会导致 csv-indexer 失败,而不会使现有文档或其他索引器不可用。 有关计划选项和详细状态字段,请参阅 “计划索引器 ”和 “监视索引器”状态。

  • 保持直接 JSON 和 CSV 密钥稳定且全局唯一。 不要在管道之间重复使用密钥。

  • 预计 DOCX 投影将重新运行,以通过子文档与父文档之间的关系,使过期的子文档保持一致。 生成的子键可能会发生变化,因此应通过 parentId 来识别投影组,而不是预测子键。 有关投影生命周期的详细信息,请参阅 内容生命周期。

  • 在依赖已删除的 DOCX 父 blob 来删除其投影子项之前,请先配置适当的 blob 删除检测策略。

Caution

直接的一对多解析需要由应用程序负责清理。 Blob 删除检测策略不适用于从 JSON 数组元素或 CSV 行创建的搜索文档。 删除某个元素或行,或者删除其源 Blob,可能会导致目标文档仍保留在索引中。 使用 Delete 文档 显式删除每个孤立项,或者从权威文档键集中重新生成索引。

Troubleshooting

下表列出了运行三个管道时的常见问题和解决方法。

症状 可能的原因 解决方案
lastResult.itemsFailed 大于零 源文档的格式异常,或者嵌入技能接收到空文本。 检查 lastResult.errors 索引器状态响应中是否存在特定错误消息和失败的文档密钥。
所有索引器均成功后,@odata.count 仍低于预期 索引器尚未完成其运行,DOCX 生成了不同的区块数,或键冲突重写了文档。 等待所有三个索引器报告 success。 确认显示所有三 sourceType 个值,并验证 JSON 和 CSV 密钥是否使用不同的前缀(json_, csv_)。
矢量查询返回零结果 索引中的向量器配置与索引时使用的嵌入模型不匹配,或者没有文档填充 contentVector 值。 确认向量化器的 deploymentId 和 modelName 与技能组中的值匹配。 确认 DOCX 和 CSV 索引器已完成,且无失败。
JSON 文档显示在矢量查询结果中 JSON 索引器意外填充了 contentVector。 确认 json-indexer 没有以 contentVector 为目标的 outputFieldMappings。 JSON 记录应将 contentVector 保留为 null。
CSV 索引器失败并出现分析错误 CSV 文件具有未转义的逗号、不匹配的引号或编码问题。 打开 CSV 文件并验证带逗号的字段是否括在双引号中。 使用 UTF-8 编码保存文件。
"The index 'multi-source-index' was not found" 查询期间出错 未创建索引,或者已将查询发送到错误的搜索服务。 确认 <search-endpoint> 是否指向正确的服务。 运行 GET <search-endpoint>/indexes?api-version=2026-08-01-preview 以列出索引。
运行索引器请求返回 HTTP 411 Length Required POST 请求没有正文,REST 客户端没有发送 Content-Length 标头。 将 Content-Length: 0 添加到请求标头中。 某些 REST 客户端需要显式将此标头用于具有空正文的 POST 请求。
重新运行显示 itemsProcessed 等于 0 自上次运行以来,源 Blob 未发生变化。 这是预期的行为。 索引器使用变更检测,并跳过未发生变化的 Blob 对象。 若要强制重新处理,请先通过发送 POST <search-endpoint>/indexers/<indexer-name>/reset?api-version=2026-08-01-preview 和 Content-Length: 0 持有者令牌标头来重置索引器。

清理资源

如果不再需要在本教程中创建的Azure AI 搜索对象,请按以下依赖项顺序将其删除:

  1. 删除索引器:

    DELETE <search-endpoint>/indexers/docx-indexer?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    
    DELETE <search-endpoint>/indexers/json-indexer?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    
    DELETE <search-endpoint>/indexers/csv-indexer?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:删除索引器(REST API)

    每次删除操作都会在成功时返回 HTTP 204 No Content 。 如果收到 404 Not Found,则索引器已被删除。

  2. 删除技能集:

    DELETE <search-endpoint>/skillsets/docx-semantic-skillset?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    
    DELETE <search-endpoint>/skillsets/csv-embedding-skillset?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    参考:删除技能集 (REST API)

    每次删除操作都会在成功时返回 HTTP 204 No Content 。

  3. 删除数据源:

    DELETE <search-endpoint>/datasources/docx-blob-datasource?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    
    DELETE <search-endpoint>/datasources/json-blob-datasource?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    
    DELETE <search-endpoint>/datasources/csv-blob-datasource?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    Reference:Delete Data Source (REST API)

    每次删除操作都会在成功时返回 HTTP 204 No Content 。

  4. 删除索引:

    DELETE <search-endpoint>/indexes/multi-source-index?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    Reference:Delete Index (REST API)

    成功时返回 HTTP 204 No Content。

  5. 验证是否已删除索引器:

    GET <search-endpoint>/indexers?api-version=2026-08-01-preview
    Authorization: Bearer <search-access-token>
    

    Reference:List Indexers (REST API)

    确认 docx-indexer, json-indexer并且 csv-indexer 不再出现在响应中。

  6. 如果为此练习创建了资源组,请删除它及其包含的所有资源:

    az group delete --name <resource-group-name> --yes --no-wait
    

    参考:az group delete(Azure CLI)

    该命令会立即返回并异步删除资源组及其所有资源。