Apache Arrow C++ 数组体系全解析:从 ArrayData、Array 到 ChunkedArray 与 ArrayVisitor
Apache Arrow C 数组体系全解析从 ArrayData、Array 到 ChunkedArray 与 ArrayVisitor【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址: https://gitcode.com/gh_mirrors/arrow13/arrowApache Arrow 在cpp/src/arrow/array/下构建了一套完整、统一的 C 数组Array体系docs/source/cpp/api/array.rst正是这一体系的官方 API 索引它从最底层的ArrayData开始依次覆盖抽象基类Array、工厂函数、Primitive / Temporal / Binary-like / Nested / Dictionary / Extension 等具体数组子类以及逻辑上把多个 Array 聚合成一个大数组的ChunkedArray最后以类型分发的ArrayVisitor收尾。本文以该文档为主线结合仓库源码逐层剖析这套体系的类层次、内存布局、访问器语义与常用工具读完你将对 Arrow C 中一个数组到底长什么样、如何构造、如何读写、如何切分与验证有完整认识并能直接对照源码继续深挖任意一个具体数组类型。ArrayData数组内存的通用容器arrow::ArrayData是整棵数组类树的地基array.rst将它与Array并列放在文档最前面。它在 cpp/src/arrow/array/data.h 中定义注释里明确它的定位一个自包含的、描述 Arrow 数组内存与元数据的容器相当于 Java 实现中的 Vector而arrow::Array及其子类则提供强类型访问器并支持访问者模式visitor pattern。核心成员与构造ArrayData的核心字段包括字段类型含义typestd::shared_ptrDataType数组的逻辑类型如int64、utf8、listlengthint64_t数组元素个数null_countint64_t原子物理空值个数未知时用kUnknownNullCount -1表示首次访问时惰性计算offsetint64_t相对父数组数据的偏移用于零拷贝切片默认为 0buffersstd::vectorstd::shared_ptrBuffer数据缓冲区列表buffers[0]通常是有效性位图validity bitmapchild_datastd::vectorstd::shared_ptrArrayData嵌套类型的子数组数据如 List 的值数组、Struct 的字段数组dictionarystd::shared_ptrArrayData字典数组专用的字典数据null_count -1这一设计来自 ARROW-33见 data.h 注释切片时并不知道切片范围的空值个数为避免急切计算先置为负数当Array::null_count()第一次被调用时才计算并缓存。ArrayData还提供多个Make静态工厂data.h#L126-L146支持仅传类型与长度、带 buffers、带 child_data、带 dictionary 四种形态。缓冲区访问ArrayData提供了一组模板化访问器GetValuesT(i, absolute_offset)把第 i 个 buffer 按类型 T 解释为指针GetValuesSafeT在缓冲区非 CPU buffer 时返回NULLPTR而不是崩溃GetMutableValuesT则拿到可写指针。Slice(offset, length)构造零拷贝切片不复制底层 buffer只调整 offset/lengthSliceSafe是带边界检查的版本。空值判定物理与逻辑理解 Arrow 的空值模型要从ArrayData的几个方法入手HasValidityBitmap()buffers[0] ! NULLPTR即是否存在有效性位图。MayHaveNulls()有效性位图存在且null_count ! 0。MayHaveLogicalNulls()与ComputeLogicalNullCount()除了位图还会检查 union、run-end encoded、dictionary 这类没有位图但子数据可能含空的类型见 data.h 中对SPARSE_UNION/DENSE_UNION/RUN_END_ENCODED/DICTIONARY的分派。data.h#L321-L343还给出了一个迁移示例老代码用array.MayHaveNulls()判断是否需要检查位图新代码应改用MayHaveLogicalNulls()HasValidityBitmap()的组合才能正确处理 union 等特殊类型。一次典型的数据复用ArrayData注释data.h#L71-L77演示了最经典的用法——改类型不改内存Int64Array arr GetMyData(); auto new_data arr.data()-Copy(); new_data-type arrow::float64(); DoubleArray double_arr(new_data);由于 Int64 与 Float64 物理布局相同同为 8 字节定宽直接把ArrayData拷贝一份、替换type字段就能零拷贝得到一个新类型的数组。这也解释了为什么ArrayData被设计为可变的mutable而对外暴露的Array是不可变的immutable。Array不可变数组的抽象基类arrow::Arrayarray_base.h是所有用户可见数组类型的基类。它的设计哲学是不可变、零拷贝、内存由 Buffer 持有。基类只要求若空值个数大于 0则需要有效性位图 buffer若空值个数未知构造时可传 -1 让它惰性计算。常用访问器方法说明length()元素个数来自data_-lengthoffset()相对数据起点偏移零拷贝切片核心null_count()物理空值个数首次调用时计算并缓存ComputeLogicalNullCount()对无位图类型union、run-end encoded也给出正确的逻辑空值数IsNull(i)/IsValid(i)按索引判空/判有效不做边界检查返回booltype()/type_id()逻辑类型对象及其枚举 idnull_bitmap()/null_bitmap_data()有效性位图 buffer 及其裸指针GetScalar(i)把第 i 个元素包装为Scalar对象IsValid的实现值得注意array_base.h#L62-L80如果有效性位图存在直接用位运算bit_util::GetBit(null_bitmap_data_, i data_-offset)取值否则按类型分派——SPARSE_UNION、DENSE_UNION、RUN_END_ENCODED 调用internal命名空间下的专用函数其它类型则退化为null_count ! length。注释特别强调把IsNull做成内联、非虚函数是为了避免每次调用都走 vtable 查表这正是 Arrow 注重列式处理性能的体现。切片、比较与校验切片Slice(offset, length)是零拷贝的——它返回共享同一批 buffer 的新Array对象只更新offset与lengthSliceSafe增加输入检查。需要复制到其它设备时可用CopyTo(MemoryManager)递归拷贝全部 buffer 与子数组或ViewOrCopyTo优先尝试零拷贝视图失败再回退复制。比较Equals严格相等、ApproxEquals近似相等epsilon仅对 Float/Double 生效、RangeEquals指定区间比较Diff(other)返回格式化的统一 diff 文本底层是 cpp/src/arrow/array/diff.cc 的arrow::Diff。校验Validate()做轻量检查时间复杂度 O(k)k 为子孙节点数ValidateFull()做深度检查最坏 O(k·n)n 为数组长度适合调试阶段使用。视图View(type)在类型布局兼容的前提下零拷贝改变解释类型ToString()输出适合调试的 PrettyPrint 表示。设备device_type()返回底层数据所在设备CPU/GPU它委托给ArrayData::device_type()。层次划分FlatArray 与 PrimitiveArrayarray_base.h在Array之下还有两个中间基类FlatArray非嵌套数组的基类标记类无新增逻辑。PrimitiveArray定宽逻辑类型数组的基类持有raw_values_指针指向data_-buffers[1]索引 1 即数据缓冲区索引 0 是有效性位图并暴露values()方法。NullArray退化类型的特例NullArrayarray_base.h是 null 类型数组长度任意但每个元素都是 null。它的SetData直接置null_bitmap_data_ NULLPTR并把null_count强制设为length——不需要任何实际 buffer。工厂函数从 ArrayData 到 Arrayarray.rst的 Factory functions 一节引用了 Doxygen 组array-factories对应头文件 cpp/src/arrow/array/util.h 中的一组顶层函数函数作用MakeArray(data)根据ArrayData的type自动构造对应具体类型的Array最常用的入口MakeArrayOfNull(type, length, pool)构造指定类型、指定长度的全 null 数组MakeArrayFromScalar(scalar, length, pool)用标量值填充指定长度的数组其中MakeArrayOfNull与MakeArrayFromScalar返回Resultstd::shared_ptrArrayutil.h#L49-L58需要处理错误状态。实际生产代码中从 IPC 读取或从 Builder 构建出ArrayData之后通常就通过MakeArray拿到类型安全的Array对象。这些工厂函数底层依赖各具体类型构造函数按类型分派可在 cpp/src/arrow/array/array_base.cc 与 util.cc 中查看实现。具体数组子类array.rst把具体子类分成五组下面分别对应到源码文件。Primitive 与 Temporal原始与时间类型这一组包括NullArray、BooleanArray和numeric-arrays组。BooleanArrayarray_primitive.h布尔值按位紧凑存储1 元素占 1 bitValue(i)用bit_util::GetBit读取并提供false_count()/true_count()不缓存、每次重算以及begin()/end()迭代器。operator[](i)返回std::optionalboolnull 槽位返回std::nullopt。NumericArrayTYPEarray_primitive.h#L86-L120模板类按对应DataType子类实例化例如NumericArrayInt8Type、NumericArrayDate32Typevalue_type取TypeClass::c_type如int64_t、double。raw_values()返回已叠加 slice offset 的裸指针Value(i)直接下标读取operator[](i)返回std::optionalvalue_type。文档引用的numeric-arrays组覆盖整型Int8/16/32/64、UInt8/16/32/64、浮点HalfFloat、Float、Double、Decimal128/256以及时间类型Date32/64、Time32/64、Timestamp、Duration、Month/DayTime/MonthDayNano Interval。它们都有便捷别名如Int32Array即NumericArrayInt32Type。Binary-like二进制类binary-arrays组array_binary.h包括BinaryArray/StringArray定偏移int32的变长二进制/字符串value_offset(i)与value_length(i)决定第 i 个值的位置与长度LargeBinaryArray/LargeStringArrayint64 偏移版本支持超过 2 GiB 的单数组FixedSizeBinaryArray定宽二进制BinaryViewArray/StringViewArrayview 类型把短值内联、长值用 view 结构引用减少拷贝Decimal128Array/Decimal256Array在 array_decimal.h 中定义。注意 2 GiB 上限与普通 BinaryArray 偏移用 int32 有关——这正是 Large 系列存在的意义。Nested嵌套类型nested-arrays组array_nested.h包含ListArray/LargeListArray基于value_offsets缓冲区和子values数组FromArrays(offsets, values, ...)工厂负责最基础的偏移校验array_nested.h#L172-L195若 offsets 含 null 会自动分配新 offsets 数组。ListViewArray/LargeListViewArraylist 的 view 变体偏移表示的是跨度而非前缀和。FixedSizeListArray每个槽位固定包含 n 个值无需偏移数组。MapArray键值对列表的语义封装。StructArray多个子数组按位置对齐num_fields()即字段数。SparseUnionArray/DenseUnionArray联合类型不同槽位可持有不同类型。RunEndEncodedArrayarray_run_end.h游程编码数组。所有 List 变体共享模板基类VarLengthListLikeArrayarray_nested.h#L78-L137统一提供values()、value_offsets()、value_offset(i)、value_length(i)、value_slice(i)取第 i 个列表元素为一个子数组等接口并支持FlattenRecursively()把任意深度的列表展平成非列表数组。StructArray 的Flatten()则返回每个字段独立的数组。Dictionary-encoded字典编码DictionaryArrayarray_dict.h由一个非负整数索引数组加一个字典数组组成。例如[foo, bar, foo, bar, foo, bar]配字典[bar, foo]索引就是[1, 0, 1, 0, 1, 0]文档注释原例。核心 APIindices()/dictionary()分别取索引数组与字典GetValueIndex(i)把第 i 个索引转为int64_t非性能敏感场景使用FromArrays(type, indices, dictionary)构造并校验所有索引非负且小于字典大小Transpose(type, dictionary, transpose_map, pool)配合DictionaryUnifier做字典统一后的索引转置Compact(pool)压缩字典。DictionaryUnifierarray_dict.h#L126-L180是配套工具类Unify逐字典追加并产出转置索引UnifyChunkedArray/UnifyTable可跨 chunk、跨表列统一字典最终GetResult返回最小可容纳的索引类型。它只直接支持原始值类型的字典但嵌套在复杂类型内的字典会被正确统一。Extension arrays扩展数组ExtensionArrayextension_type.h是用户自定义类型的载体它包裹一个存储数组storage arraystorage()方法返回底层数组用户类型通过继承ExtensionType定义。扩展数组在逻辑上表现为用户类型但物理存储复用现有 Arrow 布局是 Arrow 类型系统可扩展性的关键。ChunkedArray逻辑上的大数组单个Array要求内存连续而现实中的数据尤其是变长二进制、字符串往往无法或不宜一次性分配为单个大数组。ChunkedArraycpp/src/arrow/chunked_array.h正是为此而生它把一组同类型的Arraychunk聚合成一个逻辑上的大数组不需要昂贵的拼接concatenation步骤。其头文件注释还给出了两条重要约定处理函数的结果 chunk 布局不保证与输入一致——API 不把保持 chunk 布局作为契约当函数输出可能超过单个Array容量如超大BinaryArray/StringArray时官方推荐直接返回ChunkedArray而不是std::vectorArray。构造与访问ChunkedArray(chunk)单 chunk 构造ChunkedArray(chunks, type)从ArrayVector构造所有 chunk 必须同类型显式传type时允许空向量Make(chunks, type)带输入校验的构造MakeEmpty(type, pool)创建指定类型的空 ChunkedArray含一个空数组 chunk。访问接口length()各 chunk 长度之和构造时算好、null_count()全 chunk 空值总数、num_chunks()、chunk(i)/chunks()、Slice(offset, length)零拷贝跨 chunk 边界也能切、Flatten(pool)Struct 类型展开为每个字段一个 ChunkedArray、View(type)对每个 chunk 调用Array::View、GetScalar(index)。此外还有Equals、ToString等常规能力以及用于拼接 chunk 的Concatenateconcatenate.h。从源码结构看ChunkedArray 与 RecordBatch / Table 共同构成了 Arrow 的逻辑数据集层Table 的一列就是一个 ChunkedArray而列式处理引擎compute 模块、dataset/scanner几乎都以 ChunkedArray 为输入输出单位。ArrayVisitor类型分发的访问者模式array.rst最后的 Utilities 一节引用了arrow::ArrayVisitorcpp/src/arrow/visitor.h。它为一每一类具体数组声明了一个虚函数Visit(const XxxArray)覆盖从NullArray、BooleanArray、全部整型/浮点/字符串/二进制/时间/Decimal 数组到 List、Struct、Map、Union、RunEndEncoded、Dictionary、Extension 等所有类型visitor.h#L34-L69。用法分两步先继承ArrayVisitor并重写关心的Visit重载再调用array-Accept(visitor)。Array::Acceptarray_base.h会根据数组的实际类型把调用分派到对应的Visit重载从而避免手写一长串if (type Type::INT32) ... else if ...的类型分派代码。默认的Visit实现返回Status::NotImplemented因此只重写需要处理的类型即可。这是 Arrow 中编写对任意数组类型通用的遍历、序列化、比较逻辑的标准手法。小结一套体系五种层次回到array.rst的组织结构可以把 Arrow C 数组体系归纳为五层ArrayData底层可变内存容器描述 type/length/null_count/offset/buffers/children/dictionaryArray 与中间基类不可变访问层FlatArray→PrimitiveArray划分了定宽与非嵌套逻辑工厂函数MakeArray等从ArrayData/ 标量一键构建具体数组具体子类Primitive/Temporal、Binary-like、Nested、Dictionary、Extension 五大家族对应 cpp/src/arrow/array/ 下的array_primitive.h、array_binary.h、array_nested.h、array_dict.h以及extension_type.h组合与工具ChunkedArray聚合多个 Array 为逻辑大数组ArrayVisitor提供类型安全的分发遍历。要深入验证本文中的每个 API 行为可以在 cpp/src/arrow/array/array_test.cc、array_binary_test.cc、array_dict_test.cc、array_list_test.cc、concatenate_test.cc 等测试文件中找到对应的单元测试用例进一步了解数据写入方向Builder 体系可继续阅读 cpp/src/arrow/array/builder_base.h 及其同目录下的 builder 系列头文件。【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址: https://gitcode.com/gh_mirrors/arrow13/arrow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2026最新建筑速写实战:5步搞定复杂立面与光影逻辑

2026最新建筑速写实战:5步搞定复杂立面与光影逻辑

2026最新建筑速写实战:5步搞定复杂立面与光影逻辑 官方文档里那些关于透视原理的长篇大论,是不是让你看得头大,根本抓不住重点?很多刚入行的朋友或者转行的设计师,一打开教程就劝退,因为全是理论推导,却很少告诉你下笔那一刻该怎么处理线条的轻重…

2026/9/23 18:08:23 阅读更多 →
EfficientVMamba:面向图像分类的状态空间模型主干

EfficientVMamba:面向图像分类的状态空间模型主干

简介:本资源是一份面向深度学习与计算机视觉方向初学者及进阶研究者的实战项目包,聚焦轻量级图像分类模型的工程落地,解决传统CNN或ViT在边缘设备部署时计算开销大、全局建模能力弱的问题。资源基于新型视觉状态空间模型(SSM&…

2026/9/23 18:08:23 阅读更多 →
2026 Java 后端面试题大全|全套答案详解,吃透拿下后端 offer

2026 Java 后端面试题大全|全套答案详解,吃透拿下后端 offer

Java面试八股 JavaOOP面试题 1、什么是B/S架构?什么是C/S架构 2、Java都有那些开发平台? 3、什么是JDK?什么是JRE? 4、Java语言有哪些特点 5、面向对象和面向过程的区别 6、什么是数据结构? 7、Java的数据结构有那些? 8、什么是…

2026/9/23 18:08:23 阅读更多 →

最新新闻

2026最新经济制度性能优化实战:告别版本升级API噩梦

2026最新经济制度性能优化实战:告别版本升级API噩梦

2026最新经济制度性能优化实战:告别版本升级API噩梦 版本升级后 API 全变了,导致线上服务直接崩溃,这种痛感在 2026…

2026/9/23 18:45:02 阅读更多 →
Python智慧考试系统:300人考场落地的防作弊+自动阅卷方案

Python智慧考试系统:300人考场落地的防作弊+自动阅卷方案

简介:本资源是一套基于Python开发的智慧校园考试系统完整源码,面向高校计算机专业学生、教育信息化开发者及Web全栈学习者,旨在解决传统校园考试流程中试题管理低效、评分自动化程度低、成绩分析滞后等痛点。压缩包共2000个文件,主…

2026/9/23 18:45:02 阅读更多 →
Apereo CAS Groovy 审计(Groovy Audits):用 Groovy 模板完全定制审计记录的输出

Apereo CAS Groovy 审计(Groovy Audits):用 Groovy 模板完全定制审计记录的输出

后端认证鉴权单点登录 【免费下载链接】cas Apereo CAS - Identity & Single Sign On for all earthlings and beyond. 项目地址: https://gitcode.com/gh_mirrors/ca/cas 点击查看 免费下载 Apereo CAS 内置了多种审计(Audit)记录实现&…

2026/9/23 18:45:02 阅读更多 →
CNN交通标志分类实战:从GTSRB数据到PyTorch部署

CNN交通标志分类实战:从GTSRB数据到PyTorch部署

简介:围绕智慧交通场景中交通标志识别这一典型任务,资源以卷积神经网络(CNN)为主轴,提供一套可直接运行的项目实践方案,适合具备基础Python知识、希望系统学习图像分类完整流程的初学者与开发者。压缩包共包…

2026/9/23 18:45:02 阅读更多 →
Opencode 循环工作流约束设计:为 CLI 优先的 AI Agent 配置绑定护栏(loop-constraints 实战指南)

Opencode 循环工作流约束设计:为 CLI 优先的 AI Agent 配置绑定护栏(loop-constraints 实战指南)

Opencode 循环工作流约束设计:为 CLI 优先的 AI Agent 配置绑定护栏(loop-constraints 实战指南) 【免费下载链接】loop-engineering Practical patterns, starters & CLI tools for loop engineering with AI coding agents. Design sys…

2026/9/23 18:45:02 阅读更多 →
3个血泪教训:手写实现老罗和他的朋友们避坑指南

3个血泪教训:手写实现老罗和他的朋友们避坑指南

3个血泪教训:手写实现老罗和他的朋友们避坑指南 看了一堆教程还是不会写项目?别急,问题往往不在你不够聪明,而在于你一直在“调包”,却从未真正理解底层逻辑。今天咱们不聊虚的,直接切入正题。以【老罗和他的朋友们】这个典型场景为例,很多开发者在…

2026/9/23 18:44:01 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →