规范化扩展类型#

介绍#

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]}

    • 使用 dim_names 元数据表示 NCHW 顺序数据的示例

      { "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,其中结构由 datashape 字段组成,描述每行一个张量

    • 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] }

    • 一个经过排列的三维张量的示例

      { "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),采用大端序表示法,并且不对字节进行任何解释。

不透明类型(Opaque)#

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

扩展参数

  • 扩展名称:arrow.opaque

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

  • 扩展类型参数

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

    • vendor_name = 外部系统的名称。

  • 序列化描述

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

    开发者不应尝试通过规范化这些参数的特定值来启用 Opaque 的公共语义互操作性。

原理#

与非 Arrow 系统接口时,需要一种方法来处理没有等效 Arrow 类型的数据。在这种情况下,应使用 Opaque 类型,它明确表示一个不受支持的字段。其他解决方案是不够的:

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

  • 丢弃不受支持的列会误导用户关于实际的模式。

  • 可能不存在适用于该不受支持类型的扩展类型。

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

应用程序不应围绕 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 类型的例子。将该类型映射到一个普通的 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

  • 扩展类型参数

    此类型没有任何参数。

  • 序列化描述

    元数据是一个空字符串。

Parquet Variant#

Variant 表示一个值,它可能是以下之一:

  • 基本类型:一个类型和对应的值(例如 INT, STRING

  • 数组:一个有序的 Variant 值列表

  • 对象:一个无序的字符串/Variant 对(即键/值对)集合。一个对象不能包含重复的键

特别地,这提供了一种无损地表示半结构化数据的方法,这些数据在 Arrow 列中以 Parquet Variant 值的形式存储。这也提供了表示扁平化的 variant 值的能力。这个规范化扩展类型允许系统传递 Variant 编码的数据,而无需特殊处理,除非它们想直接与编码的 variant 数据交互。有关实际二进制值的样子的详细信息,请参阅 Parquet 格式规范。

  • 扩展名称:arrow.parquet.variant

  • 此扩展的存储类型是一个 Struct,它遵循以下规则:

    • 一个名为 metadata 的*非空*字段,其类型为 BinaryLargeBinaryBinaryView

    • 以下至少一个(或两者都有):

      • 一个名为 value 的字段,其类型为 BinaryLargeBinaryBinaryView。(未扁平化的 variant 仅由 metadatavalue 字段组成)

      • 一个名为 typed_value 的字段,它可以是基本类型映射ListLargeListListViewStruct

        • 如果 typed_value 字段是 ListLargeListListView,其元素**必须**是*非空*的,并且**必须**是一个 Struct,包含以下至少一个(或两者都有):

          • 一个名为 value 的字段,其类型为 BinaryLargeBinaryBinaryView

          • 一个名为 typed_value 的字段,遵循上述规则(这允许任意嵌套的数据)。

        • 如果 typed_value 字段是一个 Struct,则其字段**必须**是*非空*的,表示从对象中扁平化出来的字段,并且**必须**是一个 Struct,包含以下至少一个(或两者都有):

          • 一个名为 value 的字段,其类型为 BinaryLargeBinaryBinaryView

          • 一个名为 typed_value 的字段,遵循上述规则(这允许任意嵌套的数据)。

  • 扩展类型参数

    此类型没有任何参数。

  • 序列化描述

    扩展元数据是一个空字符串。

注意

也*允许* metadata 字段进行字典编码,首选(*但非必需*)的索引类型为 int8,或进行游程编码,首选(*但非必需*)的游程类型为 int8

注意

字段可以以任何顺序出现,因此必须通过**名称**而不是*位置*来访问。字段名称是区分大小写的。

基本类型映射#

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

社区扩展类型#

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

GeoArrow#

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