你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
注意
Azure AI 搜索可通过Azure门户、REST API 和Azure SDK获取。 它还支撑着 Foundry IQ——这是一个托管知识层,可将企业内容转化为供 Microsoft Foundry 门户中的代理使用的可复用、具备权限感知能力的知识库。
如果要对 RAG 模式或矢量化内容进行分块,则可以指定 索引投影 来控制 一对多索引,其中源内容(一个)投影到一个或多个索引(多个)。 索引投影的目的是控制父文档的元素(如文件名或创建日期)是否:
- 在单个索引中对每个子项(区块)进行重复操作
- 在同一索引中被作为独立搜索文档进行索引
- 或者,被摄入到单独的索引中
建议在单个索引中重复父字段,因为将不同的文档形状或将内容拆分为两个索引可能很难查询,尤其是在不支持索引联接的经典搜索中。
在Azure AI 搜索中,分块由技能执行,因此取决于索引器。 若要定义索引投影,请在 技能集中指定它。
先决条件
Azure AI 搜索,任何层级或区域。
一个支持的数据源,其中包含要分块的内容。
接受索引器管道输出的索引(一个或多个)。
一种对内容进行分块的功能,例如文本拆分功能。
技能集包含索引器投影,用于为一对多索引梳理数据。 如果方案包含集成向量化,技能组还可以具有其他技能,例如嵌入技能(如 AzureOpenAIEmbedding )。
选择方法
索引投影为每个“父”文档生成“子”文档(区块)。 选择如何处理父内容:
| 方法 | 描述 | 配置 |
|---|---|---|
| 单个索引,重复父字段 (建议) | 每个区块的父字段重复。 所有文档都具有统一的形状。 | 将索引器和 targetIndexName 索引投影 targetIndexName 都设置为同一索引。 将 projectionMode 设置为 skipIndexingParentDocuments. |
| 单个索引、混合文档形状 | 父文档和区块文档共存。 父文档的块字段为空。 | 将这两个 targetIndexName 值设置为同一索引。 设置为 projectionModeincludeIndexingParentDocuments (或省略,因为它是默认值)。 |
| 两个或多个单独的索引 | 元数据查找的父索引、用于搜索的子索引。 无查询时联接。 | 将索引器 targetIndexName 设置为父索引。 将索引投影 targetIndexName 设置为子索引。 数组 selectors 确定子索引的数量和构成。 |
对于大多数 RAG 方案,请使用第一种方法。 请参阅 classic RAG 示例。
建议方法的实现步骤
如果数据源支持更改跟踪,索引器会自动同步更改。
为一对多索引编制创建索引
无论是为具有重复父值的区块创建一个索引,还是为父子字段的放置单独创建索引,用于搜索的主索引都是围绕数据区块设计的。 索引架构必须具有以下字段:
唯一标识每个文档的文档键字段。 必须将其定义为
Edm.String类型,并使用keyword分析器。将每个区块与其父区块关联的字段。 它必须是类型
Edm.String。 它不能是文档键字段,并且必须filterable设置为 true。 此示例中称为parent_id,本文中将它称为 投影键值 。内容的其他字段,如文本或矢量化区块字段。
创建技能集或运行索引器之前,搜索服务必须存在索引。 在技能集selectors中定义的内容应包括这些字段。
包含父字段和子字段的单索引架构
围绕区块设计的单一索引是 RAG 和矢量搜索场景中的一种主要模式,其中父内容为每个区块重复。 通过索引投影,可以将正确的父内容与每个块相关联。
以下架构是满足索引投影要求的示例。 在此示例中:
- 父字段是parent_id和标题,它们针对每个区块重复
- 子字段为矢量区块与非矢量区块。 chunk_id是此索引的文档 ID。
可以使用Azure门户、REST API 或Azure SDK创建索引。
使用 REST 客户端或 Azure 门户 Add index 操作和 JSON 选项创建索引。
{
"name": "my_consolidated_index",
"fields": [
{"name": "chunk_id", "type": "Edm.String", "key": true, "filterable": true, "analyzer": "keyword"},
{"name": "parent_id", "type": "Edm.String", "filterable": true},
{"name": "title", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "retrievable": true},
{"name": "chunk", "type": "Edm.String","searchable": true,"retrievable": true},
{"name": "chunk_vector", "type": "Collection(Edm.Single)", "searchable": true, "retrievable": false, "stored": false, "dimensions": 1536, "vectorSearchProfile": "hnsw"}
],
"vectorSearch": {
"algorithms": [{"name": "hnsw", "kind": "hnsw", "hnswParameters": {}}],
"profiles": [{"name": "hnsw", "algorithm": "hnsw"}]
}
}
向技能集添加索引投影
索引投影在技能集定义内定义,主要定义为数组 selectors,其中每个选择器对应于搜索服务上的不同目标索引。 本部分以语法和上下文示例开头,后跟参数引用。
索引投影普遍可用。 建议使用最新的稳定 API:
下面是索引投影定义的示例有效负载,你可以使用它将文本拆分技能的各个页面输出投影为搜索索引中其自己的文档。
如果父文档带有用于文档级访问权限的元数据,例如 metadata_user_ids、metadata_group_ids 或 metadata_spo_site_url,请将这些字段包含在 mappings 中。 每个分块都必须继承这些内容,这样才能应用查询时的权限筛选器。 有关详细信息,请参阅“选择填充 ACL 字段的位置”(预览)。
"indexProjections": {
"selectors": [
{
"targetIndexName": "my_consolidated_index",
"parentKeyFieldName": "parent_id",
"sourceContext": "/document/pages/*",
"mappings": [
{
"name": "chunk",
"source": "/document/pages/*",
"sourceContext": null,
"inputs": []
},
{
"name": "chunk_vector",
"source": "/document/pages/*/chunk_vector",
"sourceContext": null,
"inputs": []
},
{
"name": "title",
"source": "/document/title",
"sourceContext": null,
"inputs": []
}
]
}
],
"parameters": {
"projectionMode": "skipIndexingParentDocuments"
}
}
参数参考
| 索引投影参数 | 定义 |
|---|---|
selectors |
包含主搜索库参数的数组,通常是围绕区块设计的索引。 可以通过指定多个选择器将内容发送到多个子索引。 在运行索引器之前,搜索服务必须存在索引架构。 |
parameters |
索引投影特定配置属性的参数字典。 |
参数具有以下元素作为其定义的一部分。
| 参数 | 定义 |
|---|---|
parameters.projectionMode |
提供索引器指令的可选参数。 有效值包括 includeIndexingParentDocuments 和 skipIndexingParentDocuments。 此参数 skipIndexingParentDocuments的最佳值为 . 分块文档是主要搜索目标时,应使用它。 如果未设置 skipIndexingParentDocumentsprojectionMode,则会自动获得includeIndexingParentDocuments,因为它是默认值。 它会在你的索引中添加额外的搜索文档,这些文档的块字段为 null,但填充有父文档特定内容。 例如,如果五个 PDF 为索引贡献 100 个区块,则索引中的文档数为 105。 为父字段创建的五个文档在分段(子)字段中具有 null 值,这使它们与索引中的大多数文档有很大区别。 因此,我们建议 projectionMode 设置为 skipIndexingParentDocuments. |
选择器具有以下元素作为其定义的一部分。
| 选择器 | 定义 |
|---|---|
selectors.targetIndexName |
索引数据所要投射存入的索引名称。 它是具有重复父字段的单个分块索引,如果对父子内容使用 单独的索引 ,则它是子索引。 |
selectors.parentKeyFieldName |
为父文档提供键的字段的名称。 |
selectors.sourceContext |
定义将数据映射到各个搜索文档的粒度的扩充注释。 有关详细信息,请参阅 技能上下文和输入注释语言。 |
selectors.mappings |
扩展数据与搜索索引中字段之间的映射数组。 每个映射都包含: name:搜索索引中应将数据编入索引的字段的名称。 source:应从中拉取数据的扩充注释路径。 每个 mapping 参数还可以以递归方式使用可选 sourceContext 和 inputs 字段定义数据,类似于 知识存储 或 整形程序技能。 根据应用程序,这些参数允许将数据塑造成搜索索引中类型的 Edm.ComplexType 字段。 部分 LLM 不支持在搜索结果中使用复杂类型,因此所使用的 LLM 决定了复杂类型映射是否有实用价值。 |
参数 mappings 非常重要。 必须显式映射子索引中的每个字段,ID 字段除外,例如文档键和父 ID。
此要求与Azure AI 搜索中的其他字段映射约定形成鲜明对比。 对于某些数据源类型,索引器可以根据类似名称或已知特征隐式映射字段(例如,Blob 索引器使用唯一的元数据存储路径作为默认文档键)。 但对于索引器投影,必须显式指定关系中“多”端的所有字段映射。
重要
不要为父键字段创建字段映射。 这样做会中断更改跟踪和同步的数据刷新。
查看字段映射
索引器与三种不同类型的字段映射相关联。 在运行索引器之前,请检查字段映射并了解何时使用每种类型。
字段映射 在索引器中定义,用于将源字段映射到索引字段。 字段映射用作数据路径,它们从源中提取数据并将其传入以进行索引编制,无需使用中间技能处理步骤。 通常,索引器可以自动映射具有相同名称和类型的字段。 仅当存在差异时,才需要显式字段映射。 在到目前为止讨论的一对多索引和模式中,可能不需要字段映射。
输出字段映射 在索引器中定义,用于将通过技能集生成的丰富内容映射到主索引中的字段。 由于块是由技能(文本拆分)创建的,因此被视为富集内容,但你不需要为块或由选择器映射定义的索引投影配置输出字段映射。
Selectors.mappings 是在技能集(skillset)中定义的,并且映射到子索引中的字段。 如果子索引还包括父字段(如 合并索引解决方案中所示),则应为每个包含内容的字段(包括父级标题字段)设置字段映射,假设希望标题显示在每个分块文档中。 如果使用 单独的父索引和子索引,则选择器应仅具有子级字段的字段映射。
注意
输出字段映射和选择器映射都接受扩充的文档树节点作为源输入。 了解如何指定每个节点的路径对于设置数据路径至关重要。 若要了解更多关于路径语法的信息,请参阅 指向增强节点的路径参考 和 技能组定义 中的示例。
运行索引器
创建数据源、索引和技能集后,即可 创建并运行索引器。 此步骤会将管道置于执行状态。
可以在处理结束后查询搜索索引以测试解决方案。
内容生命周期
根据基础数据源,索引器通常可以提供正在进行的更改跟踪和删除检测。 本部分介绍与数据刷新相关的一对多索引的内容生命周期。
对于提供更改跟踪和删除检测的数据源,索引器流程可以检测源数据中的更改。 每次运行索引器和技能集时,如果技能集或基础源数据已更改,索引投影将更新。 索引器选取的任何更改都通过扩充过程传播到索引中的投影,确保投影的数据是原始数据源中内容的当前表示形式。 数据刷新活动会记录在每个区块的投影键值中。 当基础数据发生更改时,此值将更新。
注意
虽然可以使用 索引推送 API 手动编辑投影文档中的数据,但应避免这样做。 如果源数据中的文档已更新,并且数据源已启用更改跟踪或删除检测,则会在下一个管道调用中覆盖对索引的手动更新。
更新的内容
如果将新内容添加到数据源,则下次运行索引器时,新的区块或子文档将添加到索引中。
如果修改数据源中的现有内容,则如果使用的数据源支持更改跟踪和删除检测,区块将在搜索索引中以增量方式更新。 例如,如果文档中的单词或句子发生更改,则在下一个索引器运行时更新包含该单词或句子的目标索引中的区块。 现有字段不支持其他类型的更新,例如更改字段类型和某些属性。 有关允许的更新的详细信息,请参阅 更新索引架构。
某些数据源(如 Azure 存储 默认支持基于时间戳的更改和删除跟踪。 必须为变更追踪配置其他数据源,例如 Microsoft OneLake、Azure SQL 或 Azure Cosmos DB。
已删除的内容
如果源内容不再存在(例如,如果文本缩短为具有较少的区块),则会删除搜索索引中的相应子文档。 其余子文档也会更新其密钥以包含新的哈希值,即使其内容未更改也是如此。
如果父文档从数据源中完全删除,则仅当数据源定义上定义的 dataDeletionDetectionPolicy 检测到删除时,才会删除相应的子文档。 如果没有 dataDeletionDetectionPolicy 配置并且需要从数据源中删除父文档,则应 在不再需要子文档时手动删除子文档 。
投影键值
为了确保已更新和删除的内容的数据完整性,数据刷新在一对多索引中依赖于“多”端的投影键值。 如果使用集成矢量化或导入数据向导,则投影的键值是索引分块或“多”侧的 parent_id 字段。
投影的键值是索引器为每个文档生成的唯一标识符。 它确保了唯一性,并允许更改和删除跟踪正常工作。 此键包含以下段:
- 一个随机哈希,用于保证唯一性。 如果父文档在随后的索引器运行中被更新,此哈希值会发生变化。
- 父文档的键。
- 标识生成的文档的上下文的富集注释路径。
例如,如果将具有键值“aa1b22c33”的父文档拆分为四页,则通过索引投影将其中每个页面投影为自己的文档:
- aa1b22c33
- aa1b22c33_pages_0
- aa1b22c33_pages_1
- aa1b22c33_pages_2
如果父文档在源数据中更新,则可能导致更多的分块页、随机哈希更改、添加更多页,并且将更新每个区块的内容以匹配源文档中的任何内容。
单独的父子索引示例
本部分显示了单独的父索引和子索引的示例。 这是一种不常见的模式,但你可能有最适合使用此方法的应用程序要求。 在此方案中,你将父子内容投影到两个单独的索引中。
创建两个索引架构。
每个架构都有其特定粒度的字段,父 ID 字段对两个索引通用,以便在 查找查询中使用。 主要搜索库是子索引,但可以发出查找查询来检索结果中每个匹配项的父字段。 Azure AI 搜索在查询时不支持联接,因此应用程序代码或业务流程层需要合并或整理可传递给应用或进程的结果。
父索引具有parent_id字段和标题。 parent_id 为文档键。 除非希望在父文档级别向量化字段,否则不需要矢量搜索配置。
{ "name": "my-parent-index", "fields": [ {"name": "parent_id", "type": "Edm.String", "key":true, "filterable": true}, {"name": "title", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "retrievable": true} ] }子索引具有分块字段,以及parent_id字段。 若启用了集成矢量化、计分概要文件、语义排序器或分析器,需在子索引中进行设置。
{ "name": "my-child-index", "fields": [ {"name": "chunk_id", "type": "Edm.String", "key": true, "filterable": true, "analyzer": "keyword"}, {"name": "parent_id", "type": "Edm.String", "filterable": true}, {"name": "chunk", "type": "Edm.String","searchable": true,"retrievable": true}, {"name": "chunk_vector", "type": "Collection(Edm.Single)", "searchable": true, "retrievable": false, "stored": false, "dimensions": 1536, "vectorSearchProfile": "hnsw"} ], "vectorSearch": { "algorithms": [{"name": "hsnw", "kind": "hnsw", "hnswParameters": {}}], "profiles": [{"name": "hsnw", "algorithm": "hnsw"}] }, "scoringProfiles": [], "semanticConfiguration": [], "analyzers": [] }更新索引器以指定父索引作为目标。
索引器的定义指定管道的组件。 在索引器定义中,要提供的索引名称是父索引。 如果需要父级字段的字段映射,请在 outputFieldMappings 中定义它们。 对于使用单独索引的一对多索引,索引器定义可能如以下示例所示。
{ "name": "my-indexer", "dataSourceName": "my-ds", "targetIndexName": "my-parent-index", "skillsetName" : "my-skillset", "parameters": { }, "fieldMappings": (optional) Maps fields in the underlying data source to fields in an index, "outputFieldMappings" : (required) Maps skill outputs to fields in an index, }将
indexProjections添加到技能集。下面是索引投影定义的示例,该定义指定索引器用于索引内容的数据路径。 它在索引投影定义中指定子索引名称,并指定每个子级或区块级字段的映射。 这是指定子索引名称的唯一位置。
请注意,
parameters为 null 且正在使用默认值includeIndexingParentDocuments。 索引器填充父索引。 该selectors数组用于将区块文档投影到子索引。"indexProjections": { "selectors": [ { "targetIndexName": "my-child-index", "parentKeyFieldName": "parent_id", "sourceContext": "/document/pages/*", "mappings": [ { "name": "chunk", "source": "/document/pages/*", "sourceContext": null, "inputs": [] }, { "name": "chunk_vector", "source": "/document/pages/*/chunk_vector", "sourceContext": null, "inputs": [] } ] } ], "parameters": {} }运行索引器。 如果以前运行过索引器,请记得先重置它。
您应该有两个索引包含相应的内容。 在搜索资源管理器中查询索引,以验证每个索引是否具有正确的内容。
下一步
数据分块和一对多索引是 Azure AI 搜索 中经典 RAG 模式的一部分。 继续学习以下教程和代码示例,了解有关它的详细信息。