在技能集执行期间,引擎会生成一个内存中扩充树,用于捕获每个扩充,例如已识别的实体或已翻译的文本。 本文介绍如何在扩充树中引用扩充节点,以便可以将输出传递给下游技能,或指定搜索索引字段的输出字段映射。
本文会使用示例来说明各种方案。 有关完整语法,请参阅 技能上下文和输入注释语言。
背景概念
在复习语法之前,让我们回顾一些重要的概念,以便更好地理解本文后面提供的示例。
术语 | 说明 |
---|---|
“扩充文档” | 扩充文档是一种内存中结构,在创建时收集技能输出,并保存与文档相关的所有扩充。 可以把扩充文档看作是树。 通常,树从根文档级别开始,每个新扩充都是从上一个节点创建为子节点的。 |
“节点” | 在扩充文档中,节点(有时称为“批注”)是特定输出,例如 OCR 技能的“text”或“layoutText”,或原始源字段值,例如产品 ID 字段的内容,或从源复制的元数据,例如从 Azure 存储中的 blob metadata_storage_path。 |
“上下文” | 扩充的范围,即整个文档、文档的一部分(页面或句子),或者如果使用图像,则从文档中提取的图像。 默认情况下,扩充上下文位于 "/document" 级别,作用域为数据源中的单个文档。 当一个技能运行时,该技能的输出将成为定义上下文的属性。 |
不同方案的路径
路径在技能组的“上下文”和“源”属性以及索引器的输出字段映射中指定。
屏幕截图中的示例展示了 Azure Cosmos DB 集合中某个项的路径。
context
路径为/document/HotelId
,因为集合由/HotelId
字段分区到文档中。source
路径是因为/document/Description
技能是翻译技能,而要翻译的字段是每个文档中的Description
字段。
所有路径都以 /document
开头。 扩充文档是在索引器执行的“文档破解”阶段创建的,在索引器打开文档或从数据源读取行时创建。 最初,扩充文档中唯一的节点是根节点 (/document
),它是所有其他扩充始发的节点。
以下列表包括几个常见示例:
-
/document
是根节点,指示 Azure 存储中的整个 Blob 或 SQL 表中的一行。 -
/document/{key}
是 Azure Cosmos DB 集合中文档或项的语法,其中{key}
是实际键,如上一示例中的/document/HotelId
。 -
/document/content
指定 JSON Blob 的“内容”属性。 -
/document/{field}
是对特定字段执行的操作的语法,例如转换/document/Description
字段,如上一示例中所示。 - 如果要将大型文档分解为较小的区块进行处理,
/document/pages/*
或/document/sentences/*
将成为上下文。 如果“上下文”为/document/pages/*
,则技能会在文档中的每一页上执行一次。 由于可能有多个页面或句子,因此可以追加/*
以捕获所有这些页面或句子。 - 如果文档包含图像,则会在文档破解期间创建
/document/normalized_images/*
。 图像的所有路径都以 normalized_images 开头。 由于一个文档中经常嵌入多个图像,因此追加/*
。
本文剩余部分中的示例基于“上下文”字段,该字段由 Azure blob 索引器在文档破解阶段中自动生成。 从 Blob 容器引用文档时,使用 "/document/content"
等格式,其中 content 字段是文档的一部分。
示例 1:简单注释引用
在 Azure Blob 存储中,假设有各种文件,其中包含对想要使用实体识别提取的人员名称的引用。 在以下技能定义中,"/document/content"
是整个文档的文本表示,“people”是对标识为 persons 的实体的全名提取。
因为默认上下文是 "/document"
,所以现在可以将人员列表引用为 "/document/people"
。 在此特定示例中 "/document/people"
是一个注释,它现在可以映射到索引中的一个字段,或者用在同一技能集的另一个技能中。
{
"@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
"categories": [ "Person"],
"defaultLanguageCode": "en",
"inputs": [
{
"name": "text",
"source": "/document/content"
}
],
"outputs": [
{
"name": "persons",
"targetName": "people"
}
]
}
示例 2:引用文档中的数组
此示例基于前一个示例构建,演示如何在同一个文档中多次调用一个扩充步骤。 假设前面的示例生成了一个字符串数组,其中有 10 个人名来自单个文档。 合理的下一步可能是二次扩充,将姓氏从全名中提取出来。 因为有 10 个姓名,所以你希望在这个文档中调用此步骤 10 次,每个人一次。
若要调用正确的迭代次数,请将上下文设置为 "/document/people/*"
,其中星号 ("*"
) 表示扩充文档中作为 "/document/people"
的后代的所有节点。 尽管此技能只在技能数组中定义了一次,但它会对文档中的每个成员调用,直到所有成员都被处理。
{
"@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
"description": "Fictitious skill that gets the last name from a full name",
"uri": "http://names.chinacloudsites.cn/api/GetLastName",
"context" : "/document/people/*",
"defaultLanguageCode": "en",
"inputs": [
{
"name": "fullname",
"source": "/document/people/*"
}
],
"outputs": [
{
"name": "lastname",
"targetName": "last"
}
]
}
当注释是字符串的数组或集合时,你可能希望针对特定成员而不是整个数组。 上一个示例生成上下文所表示的每个节点下调用 "last"
的批注。 如果想要引用此系列的注释,可以使用语法 "/document/people/*/last"
。 如果想要引用特定注释,可以使用显式索引:"/document/people/1/last
引用文档中标识的第一个人的姓氏。 请注意,在此语法中数组的“索引从 0 开始”。
示例 3:引用数组中的成员
有时,需要对特定类型的所有注释进行分组,以将它们传递给特定技能。 考虑一种假设的自定义技能,它标识在示例 2 中提取的所有姓氏中最常见的姓氏。 若要只将姓氏提供自定义技能,请将上下文指定为 "/document"
,将输入为指定为 "/document/people/*/lastname"
。
请注意,"/document/people/*/lastname"
的基数大于文档的基数。 可能有 10 个姓氏节点,而此文档只有一个文档节点。 在这种情况下,系统将自动创建包含文档中的所有元素的 "/document/people/*/lastname"
数组。
{
"@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
"description": "Fictitious skill that gets the most common string from an array of strings",
"uri": "http://names.chinacloudsites.cn/api/MostCommonString",
"context" : "/document",
"inputs": [
{
"name": "strings",
"source": "/document/people/*/lastname"
}
],
"outputs": [
{
"name": "mostcommon",
"targetName": "common-lastname"
}
]
}
注释路径故障排除提示
如果在指定技能输入时遇到问题,以下提示可以帮助顺利操作:
对数据运行“导入数据”向导,查看向导生成的技能组定义和字段映射。
在某个技能组上启动调试会话,查看扩充文档的结构。 可以编辑技能定义的路径和其他部分,然后运行技能来验证更改。