规范扩展类型#
介绍#
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]号维度)。如果张量的逻辑顺序是物理顺序(行优先)的排列,则置换(permutation)非常有用。
当逻辑布局和物理布局相等时,置换将始终为 ([0, 1, .., N-1]),因此可以省略。
序列化描述
元数据必须是一个有效的 JSON 对象,包括以数组形式表示的所含张量形状(键为 “shape”),以及可选的维度名称(键为 “dim_names”)和维度排序(键为 “permutation”)。
示例:
{ "shape": [2, 5]}带有 NCHW 有序数据
dim_names元数据的示例{ "shape": [100, 200, 500], "dim_names": ["C", "H", "W"]}置换后的 3 维张量示例
{ "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]号维度)。如果张量的逻辑顺序是物理顺序(行优先)的排列,则置换(permutation)非常有用。
当逻辑布局和物理布局相等时,置换将始终为 ([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] }置换后的 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]。
注意
可变形状张量扩展数组中的元素以行优先/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 的公共语义互操作性。
原理#
与非 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 布尔类型那样仅使用 1 位。虽然不如原始表示紧凑,但 Bool8 在与同样使用 1 个字节存储布尔值的各种系统之间可能具有更好的零拷贝兼容性。
扩展名称:
arrow.bool8。该扩展的存储类型为
Int8,其中false 由值
0表示。true 可以使用任何非零值指定。最好是
1。
扩展类型参数
该类型没有任何参数。
序列化描述
元数据为空字符串。
Parquet 变体 (Variant)#
Variant 表示一个值,该值可以是以下之一
基元:类型和相应的值(例如
INT,STRING)数组:Variant 值的有序列表
对象:字符串/Variant 对的无序集合(即键/值对)。对象不得包含重复键
特别是,这提供了一种以无损方式表示存储在 Arrow 列中 Parquet 变体 值内的半结构化数据的方法。这也提供了表示 碎片化 (shredded) 变体值的能力。规范扩展类型允许系统在不需要直接与编码的变体数据交互的情况下传递变体编码数据,无需特殊处理。有关实际二进制值样式的详细信息,请参阅 Parquet 格式规范。
扩展名称:
arrow.parquet.variant。该扩展的存储类型是一个遵循以下规则的
Struct一个名为
metadata的非空字段,其类型为Binary,LargeBinary或BinaryView。至少包含以下其中一项(或两者)
一个名为
value的字段,其类型为Binary,LargeBinary或BinaryView。(未碎片化的变体仅包含metadata和value字段)一个名为
typed_value的字段,它可以是 基元类型映射 或List,LargeList,ListView或Struct如果
typed_value字段是List,LargeList或ListView,其元素必须是非空的,并且必须是一个至少包含以下其中一项(或两者)的Struct一个名为
value的字段,其类型为Binary,LargeBinary或BinaryView。一个名为
typed_value的字段,它遵循上述规则(这允许任意嵌套数据)。
如果
typed_value字段是Struct,则其字段必须是非空的,表示从对象中碎片化的字段,并且必须是一个至少包含以下其中一项(或两者)的Struct一个名为
value的字段,其类型为Binary,LargeBinary或BinaryView。一个名为
typed_value的字段,它遵循上述规则(这允许任意嵌套数据)。
扩展类型参数
该类型没有任何参数。
序列化描述
扩展元数据为空字符串。
注意
metadata 字段使用首选(非必需)索引类型为 int8 的字典编码,或使用首选(非必需)运行类型为 int8 的游程编码(run-end-encoded)也是允许的。
注意
字段可以是任何顺序,因此必须通过名称而不是位置来访问。字段名称区分大小写。
基元类型映射#
Arrow 基元类型 |
Variant 基元类型 |
|---|---|
Null |
Null |
Boolean |
Boolean (true/false) |
Int8 |
Int8 |
Uint8 |
Int16 |
Int16 |
Int16 |
Uint16 |
Int32 |
Int32 |
Int32 |
Uint32 |
Int64 |
Int64 |
Int64 |
Float |
Float |
Double |
Double |
十进制数32 |
decimal4 |
十进制数64 |
decimal8 |
Decimal128 |
decimal16 |
Date32 |
日期型 (Date) |
Time64 |
TimeNTZ |
Timestamp(us, UTC) |
Timestamp (micro) |
Timestamp(us) |
TimestampNTZ (micro) |
Timestamp(ns, UTC) |
Timestamp (nano) |
Timestamp(ns) |
TimestampNTZ (nano) |
Binary |
Binary |
大二进制 |
Binary |
BinaryView |
Binary |
String |
String |
LargeString |
String |
StringView |
String |
UUID 扩展类型 |
UUID |
带偏移量的时间戳#
此类型表示一个时间戳列,该列存储每个值可能不同的时区偏移量。时间戳以 UTC 格式存储,并附带原始时区偏移量(以分钟为单位)。此扩展类型旨在与多个数据库引擎支持的 ANSI SQL 的 TIMESTAMP WITH TIME ZONE 兼容。
扩展名称:
arrow.timestamp_with_offset。该扩展的存储类型为按顺序包含 2 个字段的
Structtimestamp:非空的Timestamp(time_unit, "UTC"),其中time_unit是任何 ArrowTimeUnit(s, ms, us 或 ns)。offset_minutes:表示从 UTC 时区偏移的分钟数的非空带符号 16 位整数 (Int16)。负偏移量表示 UTC 以西的时区,正偏移量表示以东。偏移量通常在 -779 (-12:59) 到 +780 (+13:00) 之间。
扩展类型参数
该类型没有任何参数。
序列化描述
扩展元数据为空字符串。
注意
offset_minutes 字段使用字典编码或游程编码也是允许的。
社区扩展类型#
除了上面列出的规范扩展类型外,还存在在特定领域内已建立为标准的 Arrow 扩展类型。这些尚未通过 Arrow 开发邮件列表上的讨论和投票正式指定为规范,但在 Arrow 开发者的子社区中广为人知。
GeoArrow#
GeoArrow 定义了一组用于表示向量几何的 Arrow 扩展类型。它在 Arrow 地理空间子社区中广为人知。GeoArrow 规范尚未最终确定。