规范扩展类型#
介绍#
Arrow 列式格式允许定义 扩展类型,以便使用自定义语义扩展标准 Arrow 数据类型。通常,这些语义将特定于系统或应用程序。但是,共享已知扩展类型的定义是有益的,以便提高集成 Arrow 列式数据的不同系统之间的互操作性。
标准化#
规范扩展类型的标准化必须遵循以下规则
规范扩展类型在此文档中进行描述和维护。
每个规范扩展类型都需要在 Arrow 开发邮件列表上进行单独的讨论和投票。
要添加的规范文本必须遵循以下要求
它必须定义一个以“
arrow.
”开头的明确定义的扩展名称。它的参数(如果有)必须在提案中描述。
它的序列化必须在提案中描述,并且不应需要过多的实施工作或不寻常的软件依赖项(例如,可接受简单的自定义文本格式或基于 JSON 的格式)。
其预期的语义应该被描述,并且任何潜在的歧义或痛点都应该被解决或至少被提及。
扩展类型应该提交一个实现;如果是非平凡的(例如,如果参数化),最好是两个。
进行修改#
与标准 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
,其中 struct 由 data 和 shape 字段组成,描述每行的单个张量data 是一个
List
,保存张量元素(每个列表元素都是一个张量)。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 数组:列表中的每个元素都是一个 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
。此扩展的存储类型是
String
或LargeString
或StringView
。仅支持 rfc8259 中指定的 UTF-8 编码的 JSON。扩展类型参数
此类型没有任何参数。
序列化描述
元数据要么是空字符串,要么是包含空对象的 JSON 字符串。 未来可能会添加其他字段,但它们不是解释数组所必需的。
UUID#
扩展名称:
arrow.uuid
。该扩展的存储类型是长度为 16 字节的
FixedSizeBinary
。
注意
不需要或保证特定的 UUID 版本。 此扩展将 UUID 表示为具有大端表示法的 FixedSizeBinary(16),并且不会以任何方式解释这些字节。
Opaque#
Opaque 表示 Arrow 基础系统从外部(通常是非 Arrow)系统接收但无法解释的类型。 在这种情况下,它可以将 Opaque 传递给其客户端,至少表明字段存在并保留来自其他系统的类型元数据。
扩展参数
扩展名称:
arrow.opaque
。此扩展的存储类型是任何类型。 如果没有底层数据,存储类型应为 Null。
扩展类型参数
type_name = 外部系统中未知类型的名称。
vendor_name = 外部系统的名称。
序列化描述
一个有效的 JSON 对象,包含作为字段的参数。 未来可能会添加其他字段,但所有当前和未来的字段都不是解释数组所必需的。
开发者不应尝试通过规范化这些参数的特定值来启用 Opaque 的公共语义互操作性。
Rationale#
与非 Arrow 系统交互需要一种处理没有等效 Arrow 类型的数据的方法。 在这种情况下,使用 Opaque 类型,它明确表示不支持的字段。 其他解决方案是不充分的
引发错误意味着即使只有一个不支持的字段也会使所有操作都无法进行,即使(例如)用户只是想查看模式。
删除不支持的列会误导用户了解实际的架构。
不支持的类型可能不存在扩展类型。
动态生成扩展类型会错误地暗示支持。
应用程序不应围绕 vendor_name 和 type_name 建立约定。 这些参数旨在供人类最终用户了解哪些类型不受支持。 应用程序可能会尝试解释这些字段,但必须为损坏做好准备(例如,当以后使用自定义扩展类型支持该类型时)。 同样,Opaque 不是文件格式的通用容器。 诸如 MIME 类型之类的考虑因素是不相关的。 在这两种情况下,请创建一个自定义扩展类型。
示例
支持连接外部数据库的 Flight SQL 服务可能会在外部表中遇到具有不支持的类型的列。 在这种情况下,它可以使用 Opaque[Null] 类型至少报告存在具有特定名称和类型名称的列。 这使客户端知道存在一个列,但不受支持。 在这里使用 Null 作为存储类型,因为只涉及模式。
扩展元数据的示例是
{"type_name": "varray", "vendor_name": "Oracle"}
ADBC PostgreSQL 驱动程序将结果作为一系列带长度前缀的字节字段获取。 但是驱动程序并不总是知道如何解析这些字节,因为可能存在扩展(例如 PostGIS)。 它可以使用 Opaque[Binary] 仍然将这些字节返回给应用程序,应用程序可能能够自己解析数据。 Opaque 将该列与实际的二进制列区分开来,并明确表明该值直接来自 PostgreSQL。(首选自定义扩展类型,但总会有驱动程序不知道的扩展。)
扩展元数据的示例是
{"type_name": "geometry", "vendor_name": "PostGIS"}
ADBC PostgreSQL 驱动程序也可能知道如何解析这些字节,但不知道预期的语义。 例如,复合类型可以为现有类型添加新的语义,有点像 Arrow 扩展类型。 在这种情况下,驱动程序将能够解析底层字节,但仍将使用 Opaque 类型。
考虑 PostgreSQL 文档中
complex
类型的示例。 将类型映射到普通的 Arrowstruct
类型会丢失意义,就像 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 Boolean 类型中那样只使用 1 位来表示布尔值。 尽管不如原始表示紧凑,但 Bool8 可能与各种也使用 1 字节存储布尔值的系统具有更好的零拷贝兼容性。
扩展名称:
arrow.bool8
。此扩展的存储类型是
Int8
,其中false 由值
0
表示。true 可以使用任何非零值指定。 最好是
1
。
扩展类型参数
此类型没有任何参数。
序列化描述
元数据是一个空字符串。
社区扩展类型#
除了上面列出的规范扩展类型之外,还存在已在特定领域内建立为标准的 Arrow 扩展类型。 这些类型尚未通过 Arrow 开发邮件列表上的讨论和投票正式指定为规范类型,但在 Arrow 开发人员的子社区中广为人知。
GeoArrow#
GeoArrow 定义了用于表示矢量几何图形的 Arrow 扩展类型集合。 它在 Arrow 地理空间子社区中广为人知。 GeoArrow 规范尚未最终确定。