规范扩展类型#
简介#
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]}
带有
dim_names
元数据的示例,用于 NCHW 排序数据{ "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
,包含张量元素(每个列表元素是一个张量)。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”** 来定义张量形状在维度子集中的定义。最小的元数据是一个空字符串。
带有
dim_names
元数据的示例,用于 NCHW 排序数据(注意,第一个逻辑维度,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]。
注意
每个 **data** 张量元素内的值按行主序/C 连续顺序存储,对应于相应的 **shape**。
JSON#
扩展名:
arrow.json
。此扩展的存储类型为
String
或LargeString
或StringView
。仅支持 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 制定约定。这些参数旨在帮助最终用户了解不支持的类型。应用程序可以尝试解释这些字段,但必须做好应对故障的准备(例如,当类型稍后通过自定义扩展类型得到支持时)。类似地,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
。
扩展类型参数
此类型没有任何参数。
序列化的描述
元数据是一个空字符串。
社区扩展类型#
除了上面列出的规范扩展类型之外,还存在 Arrow 扩展类型,它们已在特定领域内成为标准。这些尚未通过 Arrow 开发邮件列表上的讨论和投票正式指定为规范,但在 Arrow 开发人员子社区中广为人知。
GeoArrow#
GeoArrow 定义了一组用于表示矢量几何的 Arrow 扩展类型。它在 Arrow 地理空间子社区中广为人知。GeoArrow 规范尚未最终确定。