
Apache Arrow C Array API 完全指南核心类、工厂函数与 ChunkedArray 实战解析【免费下载链接】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 C 库中数组Array相关的完整 API 体系展开以官方 API 文档docs/source/cpp/api/array.rst的目录结构为主线系统讲解arrow::Array基类体系、ArrayData/ArraySpan两种数据承载方式、数组工厂函数、各类具体数组子类、字典编码与 Run-End 编码数组、扩展数组以及面向大块数据的ChunkedArray与ChunkResolver索引解析工具。读完本文你将掌握 Arrow C 中数组对象的创建、访问、切片、校验、比较与跨设备传输等核心能力并能利用ArrayFromJSONString系列工具快速构造测试数据。一、数组 API 总览一张图看懂 Arrow C 数组家族Arrow C 的数组体系遵循基类定义通用契约、子类实现具体布局的设计思路。官方 API 文档将整个数组家族划分为六大区块基类Base classesArrayStatistics、ArrayData、Array、FlatArray、PrimitiveArray工厂函数Factory functionsarray-factories组用于从ArrayData、Scalar 或空值快速创建数组具体数组子类Concrete array subclasses按布局分为 Primitive/temporal数值与时序、Binary-like二进制与字符串、Nested嵌套、Dictionary-encoded字典编码、Extension扩展、Run-end encodedRun-End 编码六类Chunked ArraysChunkedArray及其配套的ChunkLocation、TypedChunkLocation、ChunkResolver非拥有型数据类Non-owning data classArraySpan工具UtilitiesArrayVisitor与FromJSONString系列辅助函数。其中FlatArray非嵌套数组基类与PrimitiveArray定长元素数组基类的定义位于 cpp/src/arrow/array/array_base.h具体子类的声明分布在 array_primitive.h、array_binary.h、array_nested.h、array_dict.h、array_run_end.h 等头文件中。二、基类体系从 ArrayData 到 Array2.1 ArrayData数组的底层数据描述arrow::ArrayData是数组的底层数据容器它本身不关心逻辑类型只描述内存布局。一个ArrayData由以下要素构成buffers一组Buffer其中buffers[0]通常是有效性位图null bitmap其余为数据缓冲区null_count空值数量若构造时未知可传 -1kUnknownNullCount首次访问时惰性计算并缓存offset相对偏移量用于零拷贝切片child_data嵌套类型如 List、Struct的子数组数据dictionary字典编码数组的字典数据type逻辑数据类型statistics关联的ArrayStatistics统计信息。从Array的成员方法可以直观看到它几乎全部是对data_的转发见 array_base.hlength()、offset()、type()、type_id()、null_bitmap()、data()等直接读取data_的字段。2.2 ArrayStatistics数组统计信息arrow::ArrayStatistics作为ArrayData的一部分随数组携带可通过Array::statistics()访问用于保存数组的统计元数据。值得注意的一点是所有数组比较方法Equals、ApproxEquals、RangeEquals都不包含ArrayStatistics的参与即统计信息不影响数组相等性判断这一约定在 array_base.h 的注释中有明确说明。2.3 Array一切数组的基类arrow::Array是不变immutable的、带有逻辑类型与长度的数据数组其头文件注释明确了两条重要语义见 array_base.h数组内存由对应的Buffer实例或其父级拥有基类仅在null_count 0时才要求持有空值位图若构造时空值数未知传入 -1 表示在首次调用null_count()时计算并缓存。核心成员方法可分为以下几组访问与查询IsNull(i)/IsValid(i)按索引判断空值/有效值不做边界检查且实现上刻意避免虚函数调用以提升内联效率length()、offset()、null_count()、type()、type_id()GetScalar(i)取出第 i 个元素的Scalar表示ComputeLogicalNullCount()计算所有类型的逻辑空值数。对无有效性位图的类型如 Union、Run-End Encoded每次调用都会重新计算num_fields()返回子数组数量。比较与诊断Equals/ApproxEquals/RangeEquals全量相等、近似相等epsilon仅对 Float/Double 生效、区间相等比较均可通过EqualOptions定制比较选项Diff(other)返回两个数组的统一格式化差异文本ToString()返回适合调试的 PrettyPrint 表示Validate()/ValidateFull()前者做廉价校验O(k)k 为子孙数组数后者做深度校验最坏 O(k*n)。切片、视图与跨设备Slice(offset, length)零拷贝切片若长度不足会自动截断SliceSafe是带输入检查的版本View(type)零拷贝类型视图要求类型布局兼容嵌套类型深度优先遍历数据缓冲区元素尺寸必须一致否则返回错误CopyTo(memory_manager)将数组及其子数组缓冲区递归复制到目标MemoryManager设备ViewOrCopyTo(memory_manager)先尝试零拷贝视图失败则回退为复制device_type()返回数组数据所在设备类型ToTensor(allow_nulls)当数据可被合理理解为多维数值张量时如 NumericArray、FixedShapeTensorArray、嵌套 FixedSizeListArray转换为Tensor。访问者模式Accept(ArrayVisitor*)将ArrayVisitor::Visit()分发到具体的数组类型。2.4 FlatArray 与 PrimitiveArray两层中间基类FlatArray所有非嵌套数组的基类本身只是对Array的标记性继承array_base.hPrimitiveArray定长元素fixed-size logical types数组的基类新增values()访问器返回buffers[1]数据缓冲区不包含切片偏移内部还缓存了raw_values_原始指针以加速访问array_base.h。三、工厂函数快速创建数组的五种方式官方 API 文档中的array-factories组定义了四个核心工厂函数全部声明在 cpp/src/arrow/array/util.h函数签名用途MakeArraystd::shared_ptrArray MakeArray(const std::shared_ptrArrayData data)从通用ArrayData构造强类型数组实例MakeArrayOfNullResultArrayPtr MakeArrayOfNull(type, length, pool default_memory_pool())创建全部元素为 null 的数组MakeArrayFromScalarResultArrayPtr MakeArrayFromScalar(const Scalar, length, pool)用同一个标量值填充整列MakeEmptyArrayResultArrayPtr MakeEmptyArray(type, pool)创建给定类型的空数组其中MakeArrayOfNull与MakeArrayFromScalar的覆盖范围极广MakeArrayOfNull支持包括 Union 类型在内的几乎所有类型相关回归测试见 array_test.ccMakeArrayFromScalar还正确处理了切片偏移场景array_test.cc。在 Arrow 内部这些工厂被 Acero 执行引擎大量用于填充常量列与空值列例如hash_join_node.cc中就用MakeArrayFromScalar构造连接键列。典型用法#include arrow/array/util.h #include arrow/type.h using namespace arrow; // 创建 5 个元素的 int64 全空数组 ARROW_ASSIGN_OR_RAISE(auto nulls, MakeArrayOfNull(int64(), 5)); // 用标量 42 填充长度为 3 的 float64 数组 auto forty_two MakeScalar(float64(), 42.0); ARROW_ASSIGN_OR_RAISE(auto filled, MakeArrayFromScalar(*forty_two, 3));四、具体数组子类六大布局分类4.1 Primitive 与 Temporal数值与时序数组NullArray退化空值类型数组其内部实现直接把null_count强制设为length且清空位图指针array_base.hBooleanArray位压缩存储的布尔数组每个值仅占 1 bitarray_primitive.hnumeric-arrays组覆盖 Int8/16/32/64、UInt8/16/32/64、HalfFloat、Float、Double、Decimal32/64/128/256 等全部数值类型以及 Date32/64、Time32/64、Timestamp、Duration、Interval、MonthDayNano 等时序类型。它们共享NumericArray模板的底层实现。4.2 Binary-like二进制与字符串数组BinaryArray基于BaseBinaryArrayBinaryType的变长二进制数组采用偏移量缓冲区 数据缓冲区双缓冲布局StringArrayUTF-8 字符串数组继承自BinaryArrayLargeBinaryArray/LargeStringArray使用 64 位偏移量的变长数组适用于超大列BinaryViewArray/StringViewArray视图类型数组直接继承FlatArray通过内联短值 引用长值的方式减少拷贝array_binary.h。4.3 Nested嵌套数组ListArray/LargeListArray变长列表数组BaseListArrayListType模板实现FixedSizeListArray定长列表数组MapArray键值对映射数组继承自ListArrayarray_nested.hStructArray结构体数组按字段field组织子数组array_nested.hUnionArray/SparseUnionArray/DenseUnionArray联合数组Sparse 与 Dense 两种布局array_nested.h。4.4 Dictionary-encoded字典编码数组DictionaryArray将重复值编码为索引数组 字典数组两部分索引类型通常为 Int8/16/32见 array_dict.h。当列中重复值多时字典编码能显著压缩内存占用这也是 Parquet 等列式格式的默认优化手段。4.5 Extension扩展数组ExtensionArray允许用户自定义逻辑类型将其包装在底层存储类型之上见 array.h 与 extension_type.h 配套使用。用户只需实现ExtensionType并配套对应的ExtensionArray子类即可让自定义类型无缝参与 Arrow 的序列化、计算与 IPC 传输。4.6 Run-end encodedRun-End 编码数组RunEndEncodedArray以run-end 值 值的方式压缩连续重复的序列见 array_run_end.h。它没有有效性位图其逻辑空值通过内部的 run 值判断这也是ComputeLogicalNullCount()需要特殊处理它的原因。五、ChunkedArray把多个 Array 当作一个逻辑数组5.1 设计动机ChunkedArray是将一个或多个 Arrow 数组在逻辑上作为一个大数组管理的数据结构其核心注释chunked_array.h说明了设计动机性能与内存优化数据分块在全项目中被视为实现细节ChunkedArray允许收集多个Array而不必执行昂贵的拼接concatenation步骤大输出兜底当函数输出超过单个Array容量如BinaryArray/StringArray时返回ChunkedArray是唯一可行方案并行处理时也无法避免产生分块输出分块不是 API 契约处理函数可以改变结果的块布局接受多个ChunkedArray输入的 API 不应假设各输入块布局一致。5.2 核心接口构造ChunkedArray(chunk)单块、ChunkedArray(chunks, type)多块块类型必须一致显式传 type 时允许空向量、Make()带校验、MakeEmpty(type, pool)访问length()、null_count()、num_chunks()、chunk(i)、chunks()、type()、device_types()/is_cpu()操作Slice(offset, length)零拷贝切片、Flatten(pool)按 Struct 字段拆分为多个ChunkedArray、View(type)逐块零拷贝视图、GetScalar(index)比较Equals允许不同分块布局但要求类型相同、ApproxEquals校验Validate()O(km)、ValidateFull()O(kn)。5.3 ChunkLocation、TypedChunkLocation 与 ChunkResolver当需要在分块数组上做逻辑索引 → 物理位置的映射时官方 API 文档提供了三件配套工具全部实现在 chunk_resolver.hChunkLocationTypedChunkLocationint64_t的别名由chunk_index块索引与index_in_chunk块内索引组成TypedChunkLocationIndexType模板化的位置描述chunk_index取值域为[0, chunks.size()]其中chunks.size()表示越界位置当越界时index_in_chunk未定义chunk_resolver.hChunkResolver将逻辑索引增量解析为物理位置的工具类。它内部维护chunks.size() 1个偏移量offsets_[i]是第 i 块的起始逻辑索引offsets_[0] 0offsets_[chunks.size()]等于总长度并通过cached_chunk_原子缓存最近解析的块索引加速顺序访问chunk_resolver.h。关键方法Resolve(index)解析单个逻辑索引返回ChunkLocation顺序访问时命中缓存复杂度 O(1)ResolveWithHint(index, hint)以上一次解析结果作为提示避免写缓存ResolveMany(n_indices, logical_index_vec, out_vec, chunk_hint)批量解析多个逻辑索引对 signed/unsigned 整数宽度分别特化实现当块数超过IndexType上限时返回false静态方法Bisect(index, offsets, lo, hi)二分查找所在块语义类似std::upper_bound但假设偏移数组以 0 开头chunk_resolver.h。#include arrow/chunk_resolver.h #include arrow/chunked_array.h // 假设 chunked 是一个 ChunkedArray例如两块 [1,2] 和 [3,null,4] arrow::ChunkResolver resolver(chunked-chunks()); auto loc resolver.Resolve(3); // 逻辑索引 3 // loc.chunk_index 1, loc.index_in_chunk 0ChunkResolver的解析加速策略在合并merge与递归分区partitioning等顺序访问场景收益明显因为连续访问通常落在同一个块内命中cached_chunk_后无需二分查找chunk_resolver.h。六、ArraySpan非拥有型数据容器实验性ArraySpan是官方 API 文档中特别标注警告的实验性类。与ArrayData不同它不持有其所引用的数据类型与数据缓冲区文档明确警告由于该类不会保活其指向的对象和数据使用期间必须另行确保这些对象的生命周期官方建议优先使用arrow::ArrayData见 array.rst。其结构定义在 array/data.h以裸指针形式持有type、固定 3 个BufferSpanbuffers[0]为有效性位图其余为数据、length、offset、可变的null_countBufferSpan是指针 大小 owner 指针的轻量视图可通过SetBuffer由shared_ptrBuffer填充可廉价拷贝适用于shared_ptr开销不可接受的场景官方点名其用于 compute kernel 接口提供GetValuesT(i)与GetSpanT(i, length)做类型化访问以及IsNull/IsValid判断支持从ArrayData隐式构造也支持从Scalar构造FillFromScalar将其填充为指向标量数据的、长度为 1 的数组视图。七、Utilities访问者模式与 FromJSONString 系列7.1 ArrayVisitor类型安全的访问者arrow::ArrayVisitorvisitor.h是经典访问者模式的抽象基类针对每种具体数组类型定义Visit(const XArray)方法配合Array::Accept(visitor)完成运行时类型分发。它允许在不修改数组类的前提下为所有数组类型编写类型安全的遍历逻辑是compute内核与序列化模块的基础设施。7.2 FromJSONString Helpers用 JSON 快速构造测试数据这是官方 API 文档单列的实用工具组实现位于 json/from_string.h 与 json/from_string.cc包含四个函数函数签名示例ArrayFromJSONStringResultArrayPtr (type, const std::string json)ArrayFromJSONString(int64(), [2, 3, null, 7, 11])ChunkedArrayFromJSONStringResultChunkedArrayPtr (type, const std::vectorstd::string)ChunkedArrayFromJSONString(int64(), {R([5, 10]), R([null]), R([16])})DictArrayFromJSONStringResultArrayPtr (dictionary_type, indices_json, dictionary_json)DictArrayFromJSONString(dictionary(int32(), utf8()), [0, 1, 0, 2, 0, 3], R([foo, bar, baz]))ScalarFromJSONStringResultScalarPtr (type, const std::string json)ScalarFromJSONString(float64(), 42)另有DictScalarFromJSONString用于字典标量。这一系列函数支持从简单 JSON 语法构造几乎所有 Arrow 类型数值、布尔、字符串、二进制、List/FixedSizeList/LargeList、Struct支持{a: 5, b: true}对象语法与数组语法两种写法、Map、Sparse/Dense Union、Decimal、Run-End Encoded、Dictionary 等还支持NaN/Inf字面量测试覆盖见 from_string_test.cc。解析严格性这些函数对输入有严格的校验from_string_test.cc中大量ASSERT_RAISES(Invalid, ...)用例表明类型不匹配如 int64 解析[0.0]、格式错误空串、[、多余的]、尾随垃圾字符、数值越界超出类型范围等都会返回Invalid状态而不是静默截断。因此在测试中直接用 JSON 字符串构造数组既直观又安全。#include arrow/json/from_string.h #include arrow/type.h using namespace arrow; // 构造一个含 null 的 int64 数组 ARROW_ASSIGN_OR_RAISE(auto arr, json::ArrayFromJSONString(int64(), [2, 3, null, 7, 11])); // 构造分块数组三块分别为 [5,10]、[null]、[16] ARROW_ASSIGN_OR_RAISE(auto chunked, json::ChunkedArrayFromJSONString(int64(), {R([5, 10]), R([null]), R([16])})); // 构造字典编码数组 ARROW_ASSIGN_OR_RAISE(auto dict_arr, json::DictArrayFromJSONString(dictionary(int32(), utf8()), [0, 1, 0, 2, 0, 3], R([foo, bar, baz])));由于它足够通用Arrow 自身的测试框架gtest_util.cc中的AssertArraysEqual等也大量依赖这些函数构造期望值与输入数据可以认为这是 Arrow 生态中事实上的数组字面量语法。八、实践建议与速查优先使用ArrayData而非ArraySpan除非你正在编写 compute kernel 且对shared_ptr开销敏感否则遵循官方警告避免生命周期管理风险大块数据用ChunkedArray并行处理、超大二进制列输出时ChunkedArray避免拼接成本跨块索引访问时配合ChunkResolver获得 O(1) 顺序解析与批量ResolveMany支持测试数据用 JSON 助手ArrayFromJSONString系列覆盖几乎所有类型且校验严格比手写 Buffer 构造高效得多设备间迁移跨 CPU/GPU 移动数据时优先ViewOrCopyTo以尝试零拷贝视图失败再回退CopyTo类型安全遍历需要按类型分派逻辑时使用ArrayVisitorAccept避免手写switch(type_id())。相关文档与源码索引API 索引页docs/source/cpp/api/array.rst基类实现array_base.h、array/data.h工厂函数array/util.h具体子类array_primitive.h、array_binary.h、array_nested.h、array_dict.h、array_run_end.h分块数组chunked_array.h、chunk_resolver.hJSON 助手json/from_string.h、json/from_string_test.cc测试参考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),仅供参考