规范扩展类型#

简介#

Arrow 列式格式允许定义扩展类型,以便使用自定义语义扩展标准 Arrow 数据类型。 通常,这些语义特定于系统或应用程序。 但是,共享众所周知的扩展类型的定义是有益的,这样可以提高集成 Arrow 列式数据的不同系统之间的互操作性。

标准化#

规范扩展类型的标准化必须遵循以下规则

  • 规范扩展类型在本文件中描述和维护。

  • 每个规范扩展类型都需要在 Arrow 开发邮件列表 上进行单独的讨论和投票。

  • 要添加的规范文本*必须* 遵循以下要求

    1. 它 *必须* 定义一个以 “arrow.” 开头的明确定义的扩展名。

    2. 其参数(如果有)*必须* 在提案中进行描述。

    3. 其序列化 *必须* 在提案中进行描述,并且不应要求过多的实现工作或不寻常的软件依赖项(例如,简单的自定义文本格式或基于 JSON 的格式是可以接受的)。

    4. 也 *应该* 描述其预期语义,并解决或至少提及任何潜在的歧义或痛点。

  • 扩展类型*应该* 提交一个实现;如果比较复杂(例如,如果参数化),最好提交两个。

进行修改#

与标准 Arrow 数据类型一样,规范扩展类型一旦标准化就应被视为稳定的。 修改规范扩展类型(例如,扩展参数集)应该是一个例外事件,遵循与上述相同的规则,并提供向后兼容性保证。

官方列表#

固定形状张量#

  • 扩展名:arrow.fixed_shape_tensor

  • 扩展的存储类型:FixedSizeList,其中

    • **value_type** 是单个张量元素的数据类型。

    • **list_size** 是张量形状中所有元素的乘积。

  • 扩展类型参数

    • **value_type** = 单个张量元素的 Arrow 数据类型。

    • **shape** = 包含的张量的物理形状,表示为数组。

    描述逻辑布局的可选参数

    • **dim_names** = 张量维度的显式名称,表示为数组。 其长度应等于形状长度,并且等于维度数。

      如果维度具有众所周知的名称并且它们映射到物理布局(行优先),则可以使用 dim_names

    • **permutation** = 原始维度所需顺序的索引,定义为数组。

      索引包含值 [0, 1, .., N-1] 的排列,其中 N 是维度数。排列指示逻辑布局的哪个维度对应于物理张量的哪个维度(逻辑视图的第 i 个维度对应于物理张量编号为 permutations[i] 的维度)。

      如果张量的逻辑顺序是物理顺序(行优先)的排列,则排列可能很有用。

      当逻辑布局和物理布局相等时,排列将始终为 ([0, 1, .., N-1]),因此可以省略。

  • 序列化描述

    元数据必须是有效的 JSON 对象,其中包含张量的形状作为键为 **“shape”** 的数组,以及可选的维度名称(键为 **“dim_names”**)和维度顺序(键为 **“permutation”**)。

    • 示例:{ "shape": [2, 5]}

    • NCHW 排序数据的 dim_names 元数据示例

      { "shape": [100, 200, 500], "dim_names": ["C", "H", "W"]}

    • 置换的三维张量示例

      { "shape": [100, 200, 500], "permutation": [2, 0, 1]}

      这是物理布局形状,在这种情况下,逻辑布局的形状将是 [500, 100, 200]

注意

固定形状张量扩展数组中的元素按行优先/C 连续顺序存储。

注意

Arrow 中的其他数据结构包括一个 张量(多维数组),用作进程间通信机制 (IPC) 中的消息。

此结构与此规范定义的固定形状张量扩展类型无关。 相反,此扩展类型允许人们将固定形状张量用作 RecordBatch 或 Table 字段中的元素。

可变形状张量#

  • 扩展名:arrow.variable_shape_tensor

  • 扩展的存储类型为:StructArray,其中结构由描述每行单个张量的 **data** 和 **shape** 字段组成

    • **data** 是一个 List,用于保存张量元素(每个列表元素都是一个张量)。 列表的值类型是张量的值类型,例如整数或浮点类型。

    • **shape** 是张量形状的 FixedSizeList<int32>[ndim],其中列表的大小 ndim 等于张量的维度数。

  • 扩展类型参数

    • **value_type** = 单个张量元素的 Arrow 数据类型。

    描述逻辑布局的可选参数

    • **dim_names** = 张量维度的显式名称,表示为数组。 其长度应等于形状长度,并且等于维度数。

      如果维度具有众所周知的名称并且它们映射到物理布局(行优先),则可以使用 dim_names

    • **permutation** = 原始维度所需顺序的索引,定义为数组。

      索引包含值 [0, 1, .., N-1] 的排列,其中 N 是维度数。排列指示逻辑布局的哪个维度对应于物理张量的哪个维度(逻辑视图的第 i 个维度对应于物理张量编号为 permutations[i] 的维度)。

      如果张量的逻辑顺序是物理顺序(行优先)的排列,则排列可能很有用。

      当逻辑布局和物理布局相等时,排列将始终为 ([0, 1, .., N-1]),因此可以省略。

    • **uniform_shape** = 各个张量维度的尺寸,保证在均匀维度中保持不变,在非均匀维度中可以变化。 这适用于数组中的所有张量。 均匀维度中的尺寸用 int32 值表示,而非均匀维度的尺寸事先未知,用 null 表示。 如果未提供 uniform_shape,则假定所有维度均为非均匀维度。 包含形状为 (2, 3, 4) 且其第一个和最后一个维度均匀的张量的数组的 uniform_shape 为 (2, null, 4)。 这允许在不考虑均匀维度的情况下正确解释张量,同时仍然允许利用均匀性的可选优化。

  • 序列化描述

    元数据必须是有效的 JSON 对象,可以选择包含维度名称(键为 **“dim_names”**)和维度顺序(键为 **“permutation”**)。 可以通过提供键 **“uniform_shape”** 在维度的子集中定义张量的形状。 最小元数据为空字符串。

    • NCHW 排序数据的 dim_names 元数据示例(请注意,第一个逻辑维度 N 映射到 **data** List 数组:List 中的每个元素都是一个 CHW 张量,并且张量列表隐式构成单个 NCHW 张量)

      { "dim_names": ["C", "H", "W"] }

    • 一组具有固定高度、可变宽度和三个颜色通道的彩色图像的 uniform_shape 元数据示例

      { "dim_names": ["H", "W", "C"], "uniform_shape": [400, null, 3] }

    • 置换的三维张量示例

      { "permutation": [2, 0, 1] }

      例如,如果单个张量的物理 **shape** 为 [100, 200, 500],则此排列将表示逻辑形状为 [500, 100, 200]

注意

permutation 外,VariableShapeTensor 的参数和存储与张量的*物理*存储相关。

例如,考虑一个具有以下内容的张量:

shape = [10, 20, 30] dim_names = [x, y, z] permutations = [2, 0, 1]

这意味着逻辑张量的名称为 [z, x, y],形状为 [30, 10, 20]。

注意

每个 **data** 张量元素内的值根据相应的 **shape** 以行优先/C 连续顺序存储。

JSON#

  • 扩展名:arrow.json

  • 此扩展的存储类型为 StringLargeStringStringView。 仅支持 rfc8259 中指定的 UTF-8 编码的 JSON。

  • 扩展类型参数

    此类型没有任何参数。

  • 序列化描述

    元数据为空字符串或带有空对象的 JSON 字符串。 将来可能会添加其他字段,但解释数组不需要这些字段。

UUID#

  • 扩展名:arrow.uuid

  • 此扩展的存储类型为 FixedSizeBinary,长度为 16 个字节。

注意

不需要或不保证特定的 UUID 版本。此扩展将 UUID 表示为 FixedSizeBinary(16),采用大端表示法,并且不以任何方式解释字节。

不透明类型#

不透明类型表示基于 Arrow 的系统从外部(通常是非 Arrow)系统接收到的类型,但它无法解释。在这种情况下,它可以将不透明类型传递给其客户端,至少表明存在一个字段并保留来自其他系统的关于该类型的元数据。

扩展参数

  • 扩展名称:arrow.opaque

  • 此扩展的存储类型可以是任何类型。如果没有底层数据,则存储类型应为 Null。

  • 扩展类型参数

    • type_name = 外部系统中未知类型的名称。

    • vendor_name = 外部系统的名称。

  • 序列化描述

    一个有效的 JSON 对象,包含参数作为字段。将来可能会添加其他字段,但当前和将来的所有字段都不是解释数组所必需的。

    开发人员**不应**尝试通过规范化这些参数的特定值来启用不透明类型的公共语义互操作性。

原理#

与非 Arrow 系统交互需要一种方法来处理没有等效 Arrow 类型的数据。在这种情况下,使用不透明类型,它显式地表示不支持的字段。其他解决方案是不够的。

  • 引发错误意味着即使只有一个不支持的字段也会使所有操作都无法进行,即使(例如)用户只是试图查看架构。

  • 删除不支持的列会误导用户了解实际架构。

  • 不支持的类型可能不存在扩展类型。

  • 动态生成扩展类型会错误地暗示支持。

应用程序**不应**围绕 vendor_name 和 type_name 制定约定。这些参数旨在供最终用户理解不支持哪种类型。应用程序可以尝试解释这些字段,但必须准备好应对中断(例如,当该类型后来通过自定义扩展类型获得支持时)。同样,**不透明类型不是文件格式的通用容器**。诸如 MIME 类型之类的考虑因素是无关紧要的。在这两种情况下,都应创建一个自定义扩展类型。

示例

  • 支持连接外部数据库的 Flight SQL 服务可能会在外部表中遇到具有不支持类型的列。在这种情况下,它可以使用 Opaque[Null] 类型至少报告存在具有特定名称和类型名称的列。这可以让客户端知道存在一个列,但不支持。此处使用 Null 作为存储类型,因为只涉及架构。

    扩展元数据的一个示例如下:

    {"type_name": "varray", "vendor_name": "Oracle"}
    
  • ADBC PostgreSQL 驱动程序将结果作为一系列长度前缀的字节字段获取。但驱动程序并不总是知道如何解析字节,因为可能存在扩展(例如 PostGIS)。它可以使用 Opaque[Binary] 将这些字节返回给应用程序,应用程序可能能够自行解析数据。不透明类型将列与实际的二进制列区分开来,并明确表示该值直接来自 PostgreSQL。(自定义扩展类型是首选,但始终存在驱动程序不知道的扩展。)

    扩展元数据的一个示例如下:

    {"type_name": "geometry", "vendor_name": "PostGIS"}
    
  • ADBC PostgreSQL 驱动程序可能也知道如何解析字节,但不知道预期的语义。例如,复合类型可以向现有类型添加新的语义,有点像 Arrow 扩展类型。在这种情况下,驱动程序将能够解析底层字节,但仍将使用不透明类型。

    考虑 PostgreSQL 文档中 complex 类型的示例。将该类型映射到普通的 Arrow struct 类型会失去意义,就像 Arrow 系统决定通过删除扩展元数据来处理所有扩展类型是不受欢迎的一样。相反,驱动程序可以使用 Opaque[Struct] 来传递复合类型信息。(尝试将其映射到 Arrow 定义的复杂类型是错误的:它不知道用户定义类型的正确语义,而这些语义不能也不应该硬编码到驱动程序中。)

    扩展元数据的一个示例如下:

    {"type_name": "database_name.schema_name.complex", "vendor_name": "PostgreSQL"}
    
  • Arrow Java 库中的 JDBC 适配器将 JDBC 结果集转换为 Arrow 数组,并且可以从结果集中获取 Arrow 模式。然而,JDBC 允许驱动程序返回任意的 Java 对象

    驱动程序可以在模式转换期间使用 Opaque[Null] 作为占位符,仅在应用程序尝试获取实际数据时才出错。这样,客户端至少可以检查结果模式以决定是否可以继续获取数据,或者只查询某些列。

    扩展元数据的一个示例如下:

    {"type_name": "OTHER", "vendor_name": "JDBC driver name"}
    

8 位布尔值#

Bool8 表示使用 1 个字节(8 位)存储每个值的布尔值,而不是像原始 Arrow 布尔类型那样只使用 1 位。尽管不如原始表示形式紧凑,但 Bool8 可能与同样使用 1 个字节存储布尔值的各种系统具有更好的零拷贝兼容性。

  • 扩展名称:arrow.bool8

  • 此扩展的存储类型为 Int8,其中

    • false 由值 0 表示。

    • 可以使用任何非零值指定 **true**。最好是 1

  • 扩展类型参数

    此类型没有任何参数。

  • 序列化描述

    元数据是一个空字符串。

社区扩展类型#

除了上面列出的规范扩展类型之外,还存在一些在特定领域内已确立为标准的 Arrow 扩展类型。这些类型尚未通过 Arrow 开发邮件列表上的讨论和投票正式指定为规范类型,但在 Arrow 开发人员子社区中是众所周知的。

GeoArrow#

GeoArrow 定义了一组用于表示矢量几何图形的 Arrow 扩展类型。它在 Arrow 地理空间子社区中广为人知。GeoArrow 规范尚未最终确定。