ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Apache Arrow C++ Compute 入门教程:Sum、CallFunction 与 IndexOptions 实战

Apache Arrow C++ Compute 入门教程:Sum、CallFunction 与 IndexOptions 实战 数据工程数据分析大数据【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow12/arrow点击查看免费下载Apache Arrow 的 C compute 模块提供了一套高效、可移植的数据计算接口让开发者可以用统一的编程模型对内存中的列式数据执行聚合、元素级运算与查找等操作。本文基于仓库 compute_tutorial.rst 与配套示例 compute_example.cc以一个完整的可编译示例为主线带你掌握三类核心用法用便捷函数Sum计算列求和、用通用入口CallFunction(add)做两列的元素级相加、用CallFunction(index)配合IndexOptions在列中搜索目标值。读完本文你将能独立编写基于 Arrow Table 的内存计算程序并理解 Datum 在计算接口中的桥梁作用。前置要求动手实践前需要准备两件事一个可用的 Arrow 安装安装与构建方式可参考 build_system 文档。对于仅运行本文示例的场景也可以直接使用仓库中现成的构建脚本详见下文「构建与运行示例」一节。对 Arrow 基础数据结构的理解本文会直接使用Array、Table、Schema、Field等结构这些内容在 basic_arrow 教程中有完整讲解包括用Int32Builder构建数组、用Schema组装Table的流程。建议先阅读该教程再继续。准备工作搭建示例骨架在编写具体计算之前需要补齐三块拼图必要的头文件、main()入口函数以及用于计算的数据。引入头文件计算功能位于 Arrow 的 compute 命名空间下示例源码 compute_example.cc 的开头这样引入依赖#include arrow/api.h #include arrow/compute/api.h #include iostream其中arrow/api.h提供Array、Table、Schema、Field、Int32Builder等核心数据结构arrow/compute/api.h则声明了Datum、Sum、CallFunction、IndexOptions等全部计算接口。iostream用于把结果打印到标准输出。main() 与 RunMain() 模式与前一篇基础数据结构教程一致示例采用「main()捕获状态 RunMain()执行逻辑」的模式见 compute_example.ccint main() { arrow::Status st RunMain(); if (!st.ok()) { std::cerr st std::endl; return 1; } return 0; }Arrow 采用返回Status/Result而非抛异常的约定RunMain()内部可以使用ARROW_RETURN_NOT_OK、ARROW_ASSIGN_OR_RAISE等宏一旦出错就带着错误状态提前返回由main()统一输出错误信息。这也解释了为什么示例的结尾会执行return arrow::Status::OK();——它向main()明确宣告一切正常。生成用于计算的数据表数据准备部分compute_example.cc沿用基础教程的ArrayBuilder手法构造一个包含两列 32 位整数的Tablearrow::Status RunMain() { // 创建两个 32 位整数数组 arrow::Int32Builder int32builder; int32_t some_nums_raw[5] {34, 624, 2223, 5654, 4356}; ARROW_RETURN_NOT_OK(int32builder.AppendValues(some_nums_raw, 5)); std::shared_ptrarrow::Array some_nums; ARROW_ASSIGN_OR_RAISE(some_nums, int32builder.Finish()); int32_t more_nums_raw[5] {75342, 23, 64, 17, 736}; ARROW_RETURN_NOT_OK(int32builder.AppendValues(more_nums_raw, 5)); std::shared_ptrarrow::Array more_nums; ARROW_ASSIGN_OR_RAISE(more_nums, int32builder.Finish()); // 用一对数组组装成表 std::shared_ptrarrow::Field field_a, field_b; std::shared_ptrarrow::Schema schema; field_a arrow::field(A, arrow::int32()); field_b arrow::field(B, arrow::int32()); schema arrow::schema({field_a, field_b}); std::shared_ptrarrow::Table table; table arrow::Table::Make(schema, {some_nums, more_nums}, 5);这里的要点Int32Builder的AppendValues接收原生 C 数组指针 长度批量追加Finish()返回Resultstd::shared_ptrArray用ARROW_ASSIGN_OR_RAISE解包。Finish()调用后 builder 状态会重置因此可以复用同一个 builder 构造第二个数组。Field描述列的「名字 数据类型」Schema决定列的集合与顺序Table::Make(schema, {col_a, col_b}, 5)把两个数组按 5 行组装成列式表。列 A 为{34, 624, 2223, 5654, 4356}列 B 为{75342, 23, 64, 17, 736}后文所有计算都基于这份数据。计算一用便捷函数 Sum() 求单列求和使用 compute 函数通常遵循「三步走」本文的第一个计算刻意把三步拆开演示准备一个用于接收输出的Datum调用便捷函数compute::Sum从Datum中取回并打印结果。用 Datum 准备输出内存所有 compute 函数的输入与输出都通过Datum传递。Datum是一个可容纳多种 Arrow 数据形态的容器可以包住Array、ChunkedArray、Scalar、RecordBatch乃至Table因此输出结果必须先落到Datum里compute_example.cc// Datum 是所有 compute 函数的输出目标同时也能作为它们的输入 arrow::Datum sum;调用 Sum()Sum是一个便捷函数convenience function它在内部封装了通用的函数调用机制把Datum转成数组后调用sum内核再把结果封装回Datum返回。在 api_aggregate.h 中它的签名是ResultDatum Sum( const Datum value, const ScalarAggregateOptions options ScalarAggregateOptions::Defaults(), ExecContext* ctx NULLPTR);注意value参数期待的是Array或ChunkedArray所以示例中用Table::GetColumnByName(A)取出列 A其返回类型正是ChunkedArray整体调用如下compute_example.cc// Sum 是便捷函数下一个计算就没有这么简单了 // 尽量使用便捷函数有助于提升可读性。 ARROW_ASSIGN_OR_RAISE(sum, arrow::compute::Sum({table-GetColumnByName(A)}));ARROW_ASSIGN_OR_RAISE会把ResultDatum成功时包裹的值赋给左侧的sum失败时直接返回错误Status。除Sum之外Arrow 还提供了大量同风格的便捷函数如Mean、MinMax、Count等具体某个函数是否有便捷版本可查阅 compute API 文档。从 Datum 取回结果Datum的灵活性意味着我们不能直接把它当作某个具体类型打印必须先确认它「装的是什么」。示例通过两个角度检查compute_example.cc// 查看 Datum 的种类及其承载内容——这里是一个 Scalar类型为 int64 std::cout Datum kind: sum.ToString() content type: sum.type()-ToString() std::endl; // 注意必须显式请求标量类型——Datum 不会自动转换 // 你需要按正确的类型去取 std::cout sum.scalar_asarrow::Int64Scalar().value std::endl;sum.ToString()报告 Datum 持有的数据形态种类此处是Scalarsum.type()-ToString()报告内部数据类型的名字此处是 64 位整数int64。整型求和会把累加结果提升到int64以避免溢出这是聚合函数的标准行为scalar_asarrow::Int64Scalar()是「显式向下转型」只有当你确信 Datum 装着Int64Scalar时才能这样取取错类型属于未定义行为这正是注释强调「必须主动询问正确类型」的原因。程序运行后本段会打印 Datum 的种类与类型随后输出求和值12891即 34 624 2223 5654 4356。计算二用 CallFunction(add) 做元素级相加Sum背后隐藏了 Arrow 计算接口的通用形态CallFunction。理解它之后你就能调用几乎全部 compute 函数。第二个示例演示如何用CallFunction完成列 A 与列 B 的逐元素相加流程与前面类似只是把「便捷函数」替换为「函数名 参数向量」。再次准备 Datum输出仍然需要一个Datumcompute_example.ccarrow::Datum element_wise_sum;以函数名调用 CallFunction()CallFunction的第一个参数是函数名字符串第二个参数是数据输入的std::vectorDatum。此处传入add与列 A、列 Bcompute_example.cc// 求列 A 与列 B 的元素级和。注意这里用的是 CallFunction() // 它的第一个参数是函数名 ARROW_ASSIGN_OR_RAISE(element_wise_sum, arrow::compute::CallFunction( add, {table-GetColumnByName(A), table-GetColumnByName(B)}));CallFunction运行时会在函数注册表中按名字查找到add内核并把输入分发到对应的执行实现上。这带来两个显著好处覆盖面广几乎所有 compute 能力都能通过函数名触发包括算术add、subtract、multiply、比较、字符串处理、集合运算等无需为每个函数写专门的封装注册表机制见 api_aggregate.cc 中便捷函数内部调用CallFunction(index, ...)的写法让底层内核与上层 API 解耦。完整的函数清单见 compute 函数列表对应文档中的compute-function-list引用结合CallFunction即可按需调用任意一个。从 Datum 取回 ChunkedArray 结果这次的结果是一整个数组因此 Datum 装的是ChunkedArray元素级运算会保持输入的形态代码同样先打印种类与类型加以确认compute_example.cc// 查看 Datum 的种类及其承载内容——这里是一个 ChunkedArray类型为 int32 std::cout Datum kind: element_wise_sum.ToString() content type: element_wise_sum.type()-ToString() std::endl; // 这次拿到的是 ChunkedArray而不是标量 std::cout element_wise_sum.chunked_array()-ToString() std::endl;Datum::chunked_array()返回std::shared_ptrChunkedArray其ToString()方法会按 chunk 输出格式化后的元素列表。实际输出为Datum kind: ChunkedArray content type: int32 [ [ 75376, 647, 2287, 5671, 5092 ] ]每一行正好是列 A 与列 B 对应元素的和3475342、62423、222364、565417、4356736。至此你已经掌握了比便捷函数更通用的CallFunction用法。计算三用 CallFunction(index) 与 IndexOptions 搜索目标值前面两个示例的输入都只是「数据本身」但很多计算还需要额外参数。Arrow 的做法是把这些参数封装在对应的 Options 结构体中随CallFunction一起传入。第三个示例以index函数为例在列 A 中查找值2223列 A 的第三个元素并返回其下标。该流程分为四步准备输出Datum构造并配置compute::IndexOptions调用CallFunction(index, ...)并传入 Options取回并打印结果。准备输出 Datum照例先声明结果容器compute_example.cc// 用 options 结构体来配置“在列 A 中搜索 2223第三个元素”这一目标 arrow::Datum third_item;用 IndexOptions 配置搜索目标IndexOptions继承自FunctionOptions其唯一成员是目标值valuestd::shared_ptrScalar定义见 api_aggregate.h/// \brief Control Index kernel behavior class ARROW_EXPORT IndexOptions : public FunctionOptions { public: explicit IndexOptions(std::shared_ptrScalar value); // Default constructor for serialization IndexOptions(); static constexpr char const kTypeName[] IndexOptions; std::shared_ptrScalar value; };构造与配置代码如下compute_example.cc// Options 结构体用于替代“可变数量参数”的传递方式 arrow::compute::IndexOptions index_options; // 注意需要的是 Arrow Scalar而不是裸的 C 值 index_options.value arrow::MakeScalar(2223);这里的关键细节是value必须是Scalar不能直接赋一个原生int32_t。arrow::MakeScalar(2223)会依据字面量推断类型并构造出对应的Int32Scalar。另外从 api_aggregate.cc 的构造函数可以看出默认构造的IndexOptions会把value初始化为NullScalar因此使用前必须显式赋值。调用 CallFunction() 并传入 OptionsOptions 以指针形式作为CallFunction的第三个参数传入compute_example.ccARROW_ASSIGN_OR_RAISE( third_item, arrow::compute::CallFunction(index, {table-GetColumnByName(A)}, index_options));第一个参数是函数名index第二个参数是输入向量此处为列 A第三个参数index_options指向配置好的 Options。index内核会扫描输入数组返回第一个等于value的元素下标找不到时返回-1。该函数同样有对应的便捷封装arrow::compute::Index见 api_aggregate.cc其实现正是return CallFunction(index, {value}, options, ctx);从侧面印证了「便捷函数 CallFunction 的薄封装」这一设计。检查搜索结果最后照例确认 Datum 内容并取值compute_example.cc// 查看 Datum 的种类及其承载内容——这里是一个 Scalar类型为 int64 std::cout Datum kind: third_item.ToString() content type: third_item.type()-ToString() std::endl; // 得到的是一个标量——2223 在列 A 中的位置基于 0 的下标为 2 std::cout third_item.scalar_asarrow::Int64Scalar().value std::endl;结果是一个Scalar内容类型为int64取出的值为2——即2223在 0 基下标体系中的第三个位置。index函数在 api_aggregate.h 中被归类为标量聚合aggregate类内核适合在列中做点查询。收尾完整程序与构建运行结束程序RunMain()的最后一行返回成功状态compute_example.ccreturn arrow::Status::OK();配合前文的main()整个程序的错误处理闭环就此完成。构建与运行示例仓库为教程示例提供了开箱即用的构建脚本build_arrow.sh 负责从 cpp 目录编译并安装 Arrow C 库默认开启ARROW_CSV、ARROW_DATASET、ARROW_FILESYSTEM、ARROW_PARQUET等组件示例本身只依赖Arrow::arrow_sharedbuild_example.sh 用 CMake 编译示例源码run.sh 串起「构建库 → 构建示例 → 运行全部示例」的完整流程其中就包括compute_example。如果你已经通过cmake --install安装了 Arrow也可以仿照 CMakeLists.txt 自行组织构建find_package(ArrowDataset)之后把compute_example.cc编成可执行文件并链接Arrow::arrow_shared即可该 CMake 文件要求的 C 标准为 C17。把三段示例拼起来完整代码见 compute_example.cc 的(Doc section: Compute Example)区间运行后依次输出Datum kind: Scalar content type: int64与12891Datum kind: ChunkedArray content type: int32与两列逐元素之和Datum kind: Scalar content type: int64与2。小结通过本文的三个递进示例你已完整覆盖了 Arrow C compute 的三类典型用法用法类别代表函数输入额外参数输出形态便捷函数compute::SumArray/ChunkedArray可选ScalarAggregateOptionsDatum(Scalar)通用调用CallFunction(add, {a, b})多个Datum无Datum(ChunkedArray)带 Options 调用CallFunction(index, {a}, opts)DatumIndexOptions指针Datum(Scalar)贯穿始终的要点有两个一是一切输入输出都经由Datum取结果时必须按实际类型显式转型scalar_asT()、chunked_array()二是函数能力通过注册表按名调用便捷函数只是CallFunction的封装因此掌握了CallFunction Options 的组合就能解锁 compute 函数列表 中的全部计算能力。当前示例处理的是完全驻留内存的数据当数据集超出内存时可以继续阅读 Arrow Datasets 教程学习如何对更大的数据规模进行相同的计算。赞分享数据工程数据分析大数据【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow12/arrow点击查看免费下载相关推荐测试实践Adaptive Tab Bar Colour 的 Selenium E2E 自动化测试全解析测试实践Adaptive Tab Bar Colour 的 Selenium E2E 自动化测试全解析 Adaptive Tab Bar Colour 是一款数据工程大数据序列化数据分析Apache Arrow C 计算引擎实战指南Sum、CallFunction 与 Options 三大用法详解Apache Arrow C 计算引擎实战指南Sum、CallFunction 与 Options 三大用法详解 Apache Arrow 的 C 计大数据数据分析数据工程序列化Apache Arrow C 入门实战从 CMake 集成、Array 构建到文件 I/O、Compute 与分区 DatasetApache Arrow C 入门实战从 CMake 集成、Array 构建到文件 I/O、Compute 与分区 Dataset 本文以官方文档 get大数据数据分析数据工程序列化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表