使用 Azure AI 搜索技能集的上下文和源属性引用扩充节点的路径

在技能集执行期间,引擎会生成一个内存中扩充树,用于捕获每个扩充,例如已识别的实体或已翻译的文本。 本文介绍如何在扩充树中引用扩充节点,以便可以将输出传递给下游技能,或指定搜索索引字段的输出字段映射。

本文会使用示例来说明各种方案。 有关完整语法,请参阅技能上下文和输入注释语言

背景概念

在复习语法之前,让我们回顾一些重要的概念,以便更好地理解本文后面提供的示例。

术语 说明
“扩充文档” 扩充文档是一种内存中结构,在创建时收集技能输出,并保存与文档相关的所有扩充。 可以把扩充文档看作是树。 通常,树从根文档级别开始,每个新扩充都是从以前的子级创建的。
“节点” 在扩充文档中,节点(有时称为“注释”)由技能(如 OCR 技能中的“text”和“layoutText”)创建和填充。 扩充文档会使用从源复制的扩充和原始源字段值或元数据填充。
“上下文” 扩充的范围,可能是整个文档、文档的一部分,或如果要使用图像,则可能是从文档中提取的图像。 默认情况下,扩充上下文位于 "/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 个 lastname 节点,而只有一个 document 节点。 在这种情况下,系统将自动创建包含文档中的所有元素的 "/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"
      }
    ]
  }

注释路径故障排除提示

如果在指定技能输入时遇到问题,以下提示可以帮助顺利操作:

  • 对数据运行“导入数据”向导,查看向导生成的技能组定义和字段映射。

  • 在某个技能组上启动调试会话,查看扩充文档的结构。 可以编辑技能定义的路径和其他部分,然后运行技能来验证更改。

另请参阅