尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Apache Arrow 规范化扩展类型(Canonical Extension Types)权威指南:从规范到源码实现

Apache Arrow 规范化扩展类型(Canonical Extension Types)权威指南:从规范到源码实现 Apache Arrow 规范化扩展类型Canonical Extension Types权威指南从规范到源码实现【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow导读Apache Arrow 列式格式允许通过扩展类型机制为标准 Arrow 数据类型附加自定义语义但各系统自定义的扩展类型往往彼此不兼容。本篇指南围绕仓库中的权威规范文档 CanonicalExtensions.rst 展开系统讲解 Arrow 规范化扩展类型Canonical Extension Types的定义规则、标准化流程以及官方列表中 8 种规范化类型固定形状张量、可变形状张量、JSON、UUID、Opaque、8 位布尔、Parquet Variant、带偏移时间戳的存储布局、参数与序列化格式并深入 Examples.rst 中 Parquet Variant 的完整编码示例。读完本文你将能够正确创建、解释和互操作这些跨系统共享的 Arrow 扩展类型并能在 C 扩展实现 与 Python 绑定 中找到对应源码佐证。一、什么是规范化扩展类型Arrow 列式格式允许定义扩展类型从而为标准 Arrow 数据类型附加自定义语义。这些语义往往特定于某个系统或应用。然而共享那些广为人知的扩展类型定义是非常有益的可以提升不同系统之间集成 Arrow 列式数据时的互操作性。为此Arrow 社区在规范文档中维护了一份“官方列表”Official List其中的类型被称为规范化扩展类型Canonical Extension Types。它们使用统一命名的扩展名以arrow.开头具有明确规定的存储类型、参数和序列化方式任何遵循该规范的实现都可以无损地解释对方的数据。在源码层面每个规范化扩展类型都有对应的 C 实现位于 cpp/src/arrow/extension 目录扩展名C 实现文件arrow.fixed_shape_tensorfixed_shape_tensor.cc / fixed_shape_tensor.harrow.variable_shape_tensorvariable_shape_tensor.cc / variable_shape_tensor.harrow.jsonjson.cc / json.harrow.uuiduuid.cc / uuid.harrow.opaqueopaque.cc / opaque.harrow.bool8bool8.cc / bool8.harrow.parquet.variantparquet_variant.cc / parquet_variant.hPython 一侧则通过 python/pyarrow/types.pxi 中的BaseExtensionType子类如FixedShapeTensorType、Bool8Type、UuidType等暴露给用户并有 test_extension_type.py 等测试文件验证其行为。二、标准化规则与修改流程规范化扩展类型并非随意添加规范文档明确规定了一套标准化流程规范化扩展类型的描述与维护都在本规范文档CanonicalExtensions.rst中进行。每种规范化扩展类型都需要在 Arrow 开发邮件列表上进行一次独立的讨论与投票。待添加的规范文本必须满足以下要求必须定义一个以arrow.开头的、明确的扩展名其参数如果有必须在提案中描述其序列化方式必须在提案中描述且不应要求过度的实现工作量或异常的软件依赖例如一个简单的自定义文本格式或基于 JSON 的格式是可以接受的其预期语义应当被描述任何潜在的歧义或痛点应当被处理或至少被提及。扩展类型应当至少有一个实现提交如果类型比较复杂例如带参数最好有两个实现。修改规则与标准 Arrow 数据类型一样规范化扩展类型一旦标准化即被视为稳定。修改一个规范化扩展类型例如扩展参数集合应当是例外事件需要遵循与上述相同的规则并提供向后兼容性保证。三、官方类型列表以下为规范文档定义的全部规范化扩展类型。3.1 Fixed shape tensor固定形状张量扩展名arrow.fixed_shape_tensor存储类型FixedSizeList其中value_type是单个张量元素的数据类型list_size是张量 shape 中所有元素的乘积。扩展类型参数value_type单个张量元素的 Arrow 数据类型shape所包含张量的物理形状以数组形式表示。可选参数描述逻辑布局dim_names张量维度的显式名称数组其长度应等于 shape 的长度也等于维度数量。当维度具有广为人知的名称并且它们映射到物理布局行主序时可以使用dim_names。permutation原始维度期望排序的索引数组。索引是[0, 1, .., N-1]N 为维度数的一个排列。permutation 指明逻辑布局的第 i 个维度对应于物理张量中编号为permutations[i]的维度。当张量的逻辑顺序是物理顺序行主序的一个排列时permutation 非常有用。当逻辑布局与物理布局一致时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]}此时物理布局 shape 为[100, 200, 500]逻辑布局 shape 为[500, 100, 200]。注意固定形状张量扩展数组中的元素以行主序row-major / C-contiguous存储。注意Arrow 中还有另一个数据结构——用于进程间通信IPC消息的Tensor多维数组它与本规范定义的 Fixed shape tensor 扩展类型没有任何关系。本扩展类型的用途是让固定形状张量可以作为 RecordBatch 或 Table 中某个字段的元素使用。源码佐证C 侧 fixed_shape_tensor.h 定义了FixedShapeTensorType类其extension_name()返回arrow.fixed_shape_tensor构造函数接收value_type、size即 list_size、shape、可选的permutation与dim_namesFixedShapeTensorArray提供FromTensor静态方法fixed_shape_tensor.h可以从一个Tensor创建数组——取 Tensor 第一维作为结果数组元素个数其余维度作为单个张量的形状若 Tensor 提供 strides 则用于确定维度置换否则假定行主序布局无置换。Python 侧types.pxi 中的FixedShapeTensorType暴露value_type、shape、dim_names、permutation属性并可通过pa.fixed_shape_tensor(pa.int32(), [2, 2])工厂函数创建。测试 test_extension_type.py 中验证了extension_name arrow.fixed_shape_tensor、各种permutation组合以及pa.FixedShapeTensorArray.from_tensor/from_numpy_ndarray的用法。3.2 Variable shape tensor可变形状张量扩展名arrow.variable_shape_tensor存储类型StructArray其中 struct 由data和shape两个字段组成每行描述一个张量data一个List存放张量元素每个 list 元素是一个张量。List 的 value type 即张量的值类型如整型或浮点型。shape一个FixedSizeListint32[ndim]存放张量形状其中 list 的大小ndim等于张量的维度数。扩展类型参数value_type单个张量元素的 Arrow 数据类型。可选参数描述逻辑布局dim_names显式维度名数组长度应等于 shape 长度与维度数。当维度具有广为人知的名称并映射到物理布局行主序时使用。permutation原始维度期望排序的索引数组语义与 Fixed shape tensor 完全相同。uniform_shape各个张量维度的尺寸其中**均匀维度uniform dimensions**的尺寸保证恒定非均匀维度可以变化该保证对数组中所有张量成立。均匀维度的尺寸用 int32 值表示非均匀维度的尺寸事先未知用 null 表示。若未提供uniform_shape则假定所有维度都是非均匀的。例如一个包含 shape 为 (2, 3, 4) 的张量、且第一个和最后一个维度均匀的数组其uniform_shape为 (2, null, 4)。这允许在不必考虑均匀维度的前提下正确解释张量同时仍允许利用均匀性进行可选的优化。序列化描述元数据必须是合法的 JSON 对象可选包含键dim_names维度名和permutation维度顺序。张量形状可通过键uniform_shape在部分维度上定义。最小元数据是空字符串。带 NCHW 数据dim_names的示例{ dim_names: [C, H, W] }注意第一个逻辑维度N映射到dataList 数组List 中的每个元素是一个 CHW 张量张量 List 隐式构成一个 NCHW 张量。带uniform_shape的示例一组高度固定、宽度可变、三个颜色通道的彩色图像{ dim_names: [H, W, C], uniform_shape: [400, null, 3] }3 维张量置换示例{ permutation: [2, 0, 1] }。若单个张量的物理 shape 为[100, 200, 500]则该置换表示逻辑 shape 为[500, 100, 200]。注意除permutation外VariableShapeTensor 的参数和存储都与张量的物理存储相关。例如一个张量shape [10, 20, 30]、dim_names [x, y, z]、permutations [2, 0, 1]意味着逻辑张量名称为[z, x, y]、逻辑 shape 为[30, 10, 20]。注意可变形状张量扩展数组中的元素以行主序row-major / C-contiguous存储。源码佐证variable_shape_tensor.cc / variable_shape_tensor.h 提供了 C 实现tensor_extension_array_test.cc 同时覆盖了固定与可变形状张量扩展数组的行为。3.3 JSON扩展名arrow.json存储类型String、LargeString或StringView。仅支持 RFC 8259 规定的 UTF-8 编码 JSON。扩展类型参数无。序列化描述元数据要么是空字符串要么是包含空对象的 JSON 字符串。未来可能增加额外字段但这些字段并非解释数组所必需。源码佐证json.cc / json.h 提供 C 实现json_test.cc 包含对应测试。3.4 UUID扩展名arrow.uuid存储类型FixedSizeBinary长度为 16 字节。注意不要求也不保证特定的 UUID 版本。本扩展类型将 UUID 表示为FixedSizeBinary(16)采用**大端big-endian**记法且不以任何方式解释字节内容。源码佐证uuid.cc / uuid.h 提供 C 实现uuid_test.cc 包含测试。Python 测试 test_extension_type.py 验证uuid_type.extension_name arrow.uuid。3.5 Opaque不透明类型Opaque 表示 Arrow 系统从外部通常是非 Arrow 的系统接收到、但无法解释的类型。此时系统可以将其以 Opaque 形式传递给客户端至少表明该字段存在并保留来自外部系统的类型元数据。扩展名arrow.opaque存储类型任意类型。如果没有底层数据存储类型应为Null。扩展类型参数type_name外部系统中未知类型的名称。vendor_name外部系统的名称。序列化描述一个以参数作为字段的合法 JSON 对象。未来可能增加额外字段但所有当前与未来的字段都不是解释数组所必需的。开发者不应试图通过规范化这些参数的特定值来启用 Opaque 的公开语义互操作性。设计动机Rationale与外部系统对接时需要一个方式来处理没有等价 Arrow 类型的数据。使用 Opaque 类型来显式表示一个不支持的字段其他方案均不充分直接报错意味着即使只有一个不支持的字段也会使所有操作无法进行哪怕用户只是想查看 schema丢弃不支持的列会误导用户对真实 schema 的判断对于不支持的类型可能根本不存在对应的扩展类型现场临时生成一个扩展类型会虚假地暗示“支持”。应用约定应用程序不应围绕vendor_name和type_name建立惯例。这两个参数是供人类最终用户理解“什么类型没有被支持”的。应用程序可以尝试解释这些字段但必须为破坏做好准备例如当该类型后来被自定义扩展类型支持时。同样Opaque 不是文件格式的通用容器MIME 类型等考虑与此无关。在上述两种情况下都应创建一个自定义扩展类型。典型示例Flight SQL 服务支持连接外部数据库时可能会在外部表中遇到类型不支持的列。此时可使用Opaque[Null]至少报告存在某个列及其名称和类型名让客户端知道列存在但不被支持。因为只涉及 schema这里用 Null 作为存储类型。扩展元数据示例{type_name: varray, vendor_name: Oracle}ADBC PostgreSQL 驱动驱动以一系列带长度前缀的字节字段返回结果但并不总能知道如何解析这些字节例如存在 PostGIS 等扩展。它可以用Opaque[Binary]把字节原样返回给应用程序由应用自行解析。Opaque 将该列与真正的二进制列区分开并明确该值直接来自 PostgreSQL自定义扩展类型更可取但驱动总会遇到不认识的扩展。元数据示例{type_name: geometry, vendor_name: PostGIS}ADBC PostgreSQL 驱动处理复合类型驱动可能知道如何解析字节但不知道其预期语义。例如 PostgreSQL 的复合类型composite types可以为既有类型添加新语义与 Arrow 扩展类型有些类似。直接映射为普通 Arrowstruct类型会丢失含义正如 Arrow 系统将所有扩展类型都丢弃扩展元数据来对待是不可取的。此时驱动使用Opaque[Struct]传递复合类型信息。元数据示例{type_name: database_name.schema_name.complex, vendor_name: PostgreSQL}Arrow Java 库的 JDBC 适配器适配器将 JDBC 结果集转换为 Arrow 数组并能从结果集获取 Arrow schema。但 JDBC 允许驱动返回任意 Java 对象java.sql.Types.OTHER。驱动可在 schema 转换期间用Opaque[Null]作为占位符仅当应用尝试获取实际数据时才报错。这样客户端至少可以检查结果 schema以决定是否继续取数或只查询某些列。元数据示例{type_name: OTHER, vendor_name: JDBC driver name}源码佐证opaque.cc / opaque.h 提供 C 实现opaque_test.cc 覆盖其行为。3.6 8-bit BooleanBool8Bool8 用1 字节8 位存储每个布尔值而原始 Arrow Boolean 类型只用 1 位。虽然不如原始表示紧凑但 Bool8 与许多同样用 1 字节存布尔值的系统具有更好的零拷贝兼容性。扩展名arrow.bool8存储类型Int8其中false用值0表示true可以用任何非零值表示优先用1。扩展类型参数无。序列化描述元数据是空字符串。源码佐证bool8.cc / bool8.h 提供 C 实现bool8_test.cc 包含测试。Python 侧 types.pxi 定义了Bool8Type可通过pa.bool8()创建。3.7 Parquet VariantVariant 表示一个可能为以下之一的值Primitive原始值一个类型及对应的值如INT、STRINGArray数组Variant 值的有序列表Object对象字符串/Variant 键值对的无序集合。对象不能包含重复键。它提供了一种方式将作为 Parquet Variant 值存储的半结构化数据以无损方式表示在 Arrow 列中也支持表示**shredded分片/剥离**的 variant 值。规范化扩展类型允许系统在无需特殊处理的情况下传递 Variant 编码数据——除非它们想直接与编码后的 variant 数据交互。关于实际二进制值的细节参见 Parquet 格式规范。扩展名arrow.parquet.variant存储类型一个遵循以下规则的Struct一个名为metadata的非空non-nullable字段类型为Binary、LargeBinary或BinaryView至少包含以下之一或两者一个名为value的字段类型为Binary、LargeBinary或BinaryView未分片的 variant 仅由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的字段或遵循上述规则的名为typed_value的字段。扩展类型参数无。序列化描述扩展元数据是空字符串。注意metadata字段也允许字典编码首选但不强制使用int8索引类型或 run-end 编码首选但不强制使用int16runs 类型。注意字段可以按任意顺序排列因此必须按名称而非位置访问。字段名区分大小写。原始类型映射表Primitive Type Mappings下表定义了 Arrow 原始类型与 Variant 原始类型的对应关系typed_value字段为原始类型时适用Arrow 原始类型Variant 原始类型NullNullBooleanBoolean (true/false)Int8Int8Uint8Int16Int16Int16Uint16Int32Int32Int32Uint32Int64Int64Int64FloatFloatDoubleDoubleDecimal32decimal4Decimal64decimal8Decimal128decimal16Date32DateTime64TimeNTZTimestamp(us, UTC)Timestamp (micro)Timestamp(us)TimestampNTZ (micro)Timestamp(ns, UTC)Timestamp (nano)Timestamp(ns)TimestampNTZ (nano)BinaryBinaryLargeBinaryBinaryBinaryViewBinaryStringStringLargeStringStringStringViewStringUUID 扩展类型UUID源码佐证parquet_variant.cc / parquet_variant.h 提供 C 实现。更详细的逐字节编码示例见下一节及 Examples.rst。3.8 Timestamp With Offset带偏移时间戳该类型表示一个每行可携带不同时区偏移的时间戳列。时间戳以 UTC 存储同时保留以分钟为单位的原始时区偏移。此扩展类型旨在兼容多种数据库引擎支持的 ANSI SQL 的TIMESTAMP WITH TIME ZONE。扩展名arrow.timestamp_with_offset存储类型一个含 2 个字段按顺序的Structtimestamp一个非空的Timestamp(time_unit, UTC)其中time_unit是任意 ArrowTimeUnits、ms、us 或 nsoffset_minutes一个非空的带符号 16 位整数Int16表示与 UTC 时区的偏移分钟数。负偏移表示 UTC 以西的时区正偏移表示以东。偏移量通常范围在 -779-12:59到 78013:00之间。扩展类型参数无。序列化描述扩展元数据是空字符串。注意offset_minutes字段也允许字典编码或 run-end 编码。四、Parquet Variant 扩展类型实战完整编码示例Examples.rst 给出了arrow.parquet.variant从最简单到任意嵌套的完整示例本节完整梳理。4.1 未分片Unshredded最简单的场景未分片的 variant恰好由两个字段组成metadata和value。以下是合法的存储类型非穷尽列表structmetadata: binary non-nullable, value: binary nullable structvalue: binary nullable, metadata: binary non-nullable structmetadata: dictionaryint8, binary non-nullable, value: binary_view nullable4.2 简单分片Simple Shredding假设一个名为measurement的 Variant 字段我们希望把int64值分片到单独的列以提升效率。在 Parquet 中可表示为required group measurement (VARIANT) { required binary metadata; optional binary value; optional int64 typed_value; }对应的arrow.parquet.variantArrow 扩展类型存储类型为struct metadata: binary non-nullable, value: binary nullable, typed_value: int64 nullable 假设一系列测量值为34, null, n/a, 100数据在 Arrow 中存储为长度 4Null count 1顶层有效性位图00001011字节 0其余为填充field-0VarBinary metadataLength 4、Null count 0偏移缓冲0, 2, 4, 6, 8值缓冲为01 00表示 version 1 空元数据重复 4 次field-1VarBinary valueLength 4、Null count 2有效性位图00000110偏移缓冲0, 0, 1, 5, 5值缓冲中00表示 null0x13 0x6E 0x2F 0x61是字面量字符串 n/a 的 variant 编码field-2int64 typed_valueLength 4、Null count 2有效性位图00001001值缓冲34, 00, 00, 100。注意value数组中有一个 variantliteral null字面量 null。这是由分片规范决定的消费者需要区分缺失的字段与为 null的字段。null 元素必须编码为 Variant null原始类型0、物理类型0。4.3 分片数组Shredding an Array考虑一个字符串数组列[comedy, drama], [horror, null], [comedy, drama, romance], null。Parquet 表示optional group tags (VARIANT) { required binary metadata; optional binary value; optional group typed_value (LIST) { # optional to allow null lists repeated group list { required group element { # shredded element optional binary value; optional binary typed_value (STRING); } } } }Variant 编码的数组结构不允许缺失元素因此数组的所有元素必须非空non-nullable。相应地每个元素要么typed_value非空要么value非空但不能两者同时非空。Arrow 中的存储类型为struct metadata: binary non-nullable, value: binary nullable, typed_value: listelement: struct value: binary nullable, typed_value: string nullable non-nullable nullable 注意如往常一样Binary也可以换成LargeBinary或BinaryViewString可以换成LargeString或StringViewList可以换成LargeList或ListView。数据在 Arrow 中的存储要点长度 4Null count 1顶层有效性位图00000111field-0metadataLength 4、Null count 0偏移0, 2, 4, 6, 8值缓冲为01 00version 1 空元数据重复 4 次field-1valueLength 4、Null count 1有效性位图00001000偏移0, 0, 0, 0, 1值缓冲00variant null——只有第 4 行整个数组为 null 的那一行需要 variant nullfield-2ListStructVarBinary, Stringtyped_valueLength 4、Null count 1有效性位图00000111偏移int320, 2, 4, 7, 7Values 数组 Length 7、Null count 0field-0VarBinary valueLength 7、Null count 6有效性位图00001000偏移0, 0, 0, 0, 1, 1, 1, 1值缓冲00variant null——即[horror, null]中那个 null 元素field-1String typed_valueLength 7、Null count 1有效性位图01110111偏移0, 6, 11, 17, 17, 23, 28, 35值缓冲拼接为comedydramahorrorcomedydramaromance。4.4 分片对象Shredding an Object考虑一个 JSON events 列其中包含我们想分片到独立列的event_type字符串和event_ts时间戳字段。Parquet 表示optional group event (VARIANT) { required binary metadata; optional binary value; # variant, remaining fields/values optional group typed_value { # shredded fields for variant object required group event_type { # event_type shredded field optional binary value; optional binary typed_value (STRING); } required group event_ts { # event_ts shredded field optional binary value; optional int64 typed_value (TIMESTAMP(true, MICROS)) } } }对应的扩展存储类型为struct metadata: binary non-nullable, value: binary nullable, typed_value: struct event_type: struct value: binary nullable, typed_value: string nullable non-nullable, event_ts: struct value: binary nullable, typed_value: timestamp(us, UTC) nullable non-nullable nullable 关键规则如果某个字段在 variant 对象值中不存在则该行对应的value和typed_value两列都为 null如果字段存在但值为 null则value必须包含一个 Variant null对给定索引value和typed_value同时非空是无效的。读者可以选择在这种场景下不报错但若如此则必须使用该索引typed_value列中的值。考虑以下对象序列{event_type: noop, event_ts: 1729794114937} {event_type: login, event_ts: 1729794146402, email: userexample.com} {error_msg: malformed...} malformed: not an object {event_ts: 1729794240241, click: _button} {event_ts: null, event_ts: 1729794954163} {event_type: noop, event_ts: 2024-10-24} {} null *Entirely missing*其 Arrow 表示要点长度 10Null count 1顶层有效性位图字节 0 为11111111、字节 1 为00000001field-0metadataVarBinaryLength 10、Null count 0偏移0, 2, 11, 24, 26, 35, 37, 39, 41, 43, 45值缓冲为各行的元数据编码如01 00version 1 空元数据、01 01 00 05 emailversion 1、1 个键值项、偏移 0、偏移 XX 为字符串长度、后续为字典字符串字节等field-1valueVarBinaryLength 10、Null count 5有效性位图字节 0 为00011110、字节 1 为00000001值缓冲中存放VariantEncode({email: useremail.com})、VariantEncode({error_msg: malformed...})、VariantEncode(malformed: not an object)、VariantEncode({click: _button})以及一个00null对应倒数第二行的null值最后一行 Entirely missing 由有效性位图标记field-2typed_valueStruct...Length 10、Null count 3有效性位图字节 0 为11110111、字节 1 为00000000event_type子字段其value列 Length 10、Null count 9只有第 1、2 行非空偏移0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1typed_value列StringLength 10、Null count 7偏移0, 4, 9, 9, 9, 9, 9, 13, 13, 13, 13值缓冲noop | login | noopevent_ts子字段value列 Length 10、Null count 9只第 7 行非空编码VariantEncode(2024-10-24)typed_value列Timestamp(us, UTC)Length 10、Null count 6有效性位图字节 0 为00110011值缓冲为时间戳1729794114937 | 1729794146402 | (null) | 1729794240241 | 1729794954163。4.5 综合示例Putting it all together如前述与 Variantvalue关联的typed_value字段可以是任意分片类型。只要遵守原始规则就可以根据分片需求产生任意数量的嵌套层级。考虑一个对象{ event_type: login, event_ts: 1729794114937, location: {longitude: 1.5, latitude: 5.5}, tags: [foo, bar, baz] }把额外字段也分片出来Parquet 表示为optional group event (VARIANT) { required binary metadata; optional binary value; # variant, remaining fields/values optional group typed_value { # shredded fields for variant object required group event_type { # event_type shredded field optional binary value; optional binary typed_value (STRING); } required group event_ts { # event_ts shredded field optional binary value; optional int64 typed_value (TIMESTAMP(true, MICROS)) } required group location { # location shredded field optional binary value; optional group typed_value { required group longitude { optional binary value; optional float64 typed_value; } required group latitude { optional binary value; optional float64 typed_value; } } } required group tags { # tags shredded field optional binary value; optional group typed_value (LIST) { repeated group list { required group element { optional binary value; optional binary typed_value (STRING); } } } } } }最终按照构造 Variant 扩展类型存储类型的规则得到struct metadata: binary non-nullable, value: binary nullable, typed_value: struct event_type: structvalue: binary nullable, typed_value: string nullable non-nullable, event_ts: structvalue: binary nullable, typed_value: timestamp(us, UTC) nullable non-nullable, location: struct value: binary nullable, typed_value: struct longitude: structvalue: binary nullable, typed_value: double nullable non-nullable, latitude: structvalue: binary nullable, typed_value: double nullable non-nullable nullable non-nullable, tags: struct value: binary nullable, typed_value: liststructvalue: binary nullable, typed_value: string nullable non-nullable nullable non-nullable nullable 可以看到分片结构通过struct嵌套与list组合递归定义每一层都遵循“value或typed_value含二者之一不可同时非空”的规则从而在 Arrow 中无损表示任意复杂度的半结构化数据。五、社区扩展类型Community Extension Types除上述规范化扩展类型外还存在一些在特定领域内被确立为标准、但尚未通过 Arrow 开发邮件列表的讨论和投票被正式指定为 canonical 的 Arrow 扩展类型它们在某些 Arrow 开发者子社区中广为人知。GeoArrow就是其中之一它定义了一组用于表示矢量几何vector geometries的 Arrow 扩展类型在 Arrow 地理空间子社区中广为人知其规范尚未最终定稿。六、总结与进一步阅读规范化扩展类型是 Arrow 生态跨系统互操作的关键设施它把“扩展标准类型”这件事本身标准化了——统一命名、明确规定存储布局与序列化并提供稳定的向后兼容承诺。本文覆盖了规范文档 CanonicalExtensions.rst 中的全部 8 种规范化类型及其标准流程并结合 Examples.rst 完整还原了 Parquet Variant 从简单到任意嵌套的编码实战。如果想继续深入建议阅读扩展类型机制的底层定义Metadata.rst8 种规范化扩展类型的 C 实现cpp/src/arrow/extensionPython 侧的公开 API 与类型定义python/pyarrow/types.pxi行为验证测试python/pyarrow/tests/test_extension_type.py、cpp/src/arrow/extension/json_test.cc、cpp/src/arrow/extension/uuid_test.cc、cpp/src/arrow/extension/opaque_test.cc、cpp/src/arrow/extension/bool8_test.cc、cpp/src/arrow/extension/tensor_extension_array_test.cc【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表