
数据工程数据分析大数据【免费下载链接】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 计算与 CSV 写入 API 提供了一套列式构建 → 矢量化计算 → 文件落盘的完整数据流水线。本文以仓库内官方示例cpp/examples/arrow/compute_and_write_csv_example.cc为主线完整讲解如何使用NumericBuilder/BooleanBuilder构建列数据、用手写循环与compute内核函数两种方式比较两列数值的大小、将结果组装成Table最后通过arrow::csv::WriteCSV输出到 CSV 文件。读完本文你将掌握 Arrow C 中数组构建、计算函数调用、Schema 组装、CSV 写出这条最小但完整的开发链路并能直接编译运行该示例验证效果。示例概览一条完整的 Arrow 数据处理流水线该示例位于仓库 cpp/examples/arrow/compute_and_write_csv_example.cc源文件内部的注释L29-L41说明了它的设计意图Many operations in Apache Arrow operate on columns of data, and the columns of data are assembled into a table. In this example, we examine how to compare two arrays which are combined to form a table that is then written out to a CSV file.整体流程可以拆解为四个阶段构建数组用arrow::NumericBuilderarrow::Int64Type构造两个各含 8 个元素的 int64 列用arrow::BooleanBuilder构造比较结果列两种方式比较先用 C 循环逐元素比较并手工写入布尔结果再调用计算内核函数greater得到同样语义的比较结果组装 Table通过arrow::schema()arrow::Table::Make()把四个列a、b、自写比较结果、Arrow 计算比较结果合并为一张表写出 CSV打开FileOutputStream调用arrow::csv::WriteCSV把表写入当前目录下的compute_and_write_output.csv。运行方式也由源码注释给出编译后直接执行./compute_and_write_csv_example程序会在当前目录生成compute_and_write_output.csv。构建示例编译条件与运行环境该示例并非无条件编译cpp/examples/arrow/CMakeLists.txt 中 L44-L46 明确if(ARROW_COMPUTE AND ARROW_CSV) add_arrow_example(compute_and_write_csv_example) endif()即只有在 CMake 配置同时开启ARROW_COMPUTE计算库与ARROW_CSVCSV 读写库两个选项时示例才会被加入构建。构建完成后可执行文件compute_and_write_csv_example会在当前工作目录生成输出文件compute_and_write_output.csv。示例头文件引入L18-L27也对应了这一依赖关系它们分别来自 Arrow 的四大公共模块arrow/api.h核心数据类型Array、Table、Builder、Statusarrow/compute/api.h计算函数CallFunction、Datumarrow/csv/api.h与arrow/csv/writer.hCSV 写入arrow/io/api.h输出流FileOutputStreamarrow/result.h/arrow/status.h错误处理宏ARROW_RETURN_NOT_OK/ARROW_ASSIGN_OR_RAISE。main函数L106-L113是典型的 Arrow 错误处理范式RunMain返回arrow::Status失败时打印错误并返回EXIT_FAILURE。第一步用 Builder 构建 int64 列Arrow 采用列式内存布局数据按列组织因此示例首先用arrow::NumericBuilderarrow::Int64Type构建两列 int64 数据L44-L61arrow::NumericBuilderarrow::Int64Type int64_builder; arrow::BooleanBuilder boolean_builder; // Make place for 8 values in total ARROW_RETURN_NOT_OK(int64_builder.Resize(8)); ARROW_RETURN_NOT_OK(boolean_builder.Resize(8)); std::vectorint64_t int64_values {1, 2, 3, 4, 5, 6, 7, 8}; ARROW_RETURN_NOT_OK(int64_builder.AppendValues(int64_values)); std::shared_ptrarrow::Array array_a; ARROW_RETURN_NOT_OK(int64_builder.Finish(array_a)); int64_builder.Reset(); int64_values {2, 5, 1, 3, 6, 2, 7, 4}; std::shared_ptrarrow::Array array_b; ARROW_RETURN_NOT_OK(int64_builder.AppendValues(int64_values)); ARROW_RETURN_NOT_OK(int64_builder.Finish(array_b));这里体现了 Builder 的标准生命周期Resize预分配容量提示 8 个槽位→AppendValues批量追加 →Finish产出不可变的Array→Reset复用同一 Builder 构建下一列。两列数据分别是{1,2,3,4,5,6,7,8}与{2,5,1,3,6,2,7,4}。随后用std::static_pointer_castarrow::Int64ArrayL64-L65把基类指针转回具体类型以便调用IsNull/Value访问器——这是拿到Array后做逐元素访问的惯用方式。第二步两种方式比较两列大小示例特意提供了两条对照路径验证手写逻辑与 Arrow 计算内核的结果一致性。方式一手写循环逐元素比较L66-L77 用一个 for 循环遍历 8 个位置先通过IsNull检查两侧是否为空再调用Value(i)取值比较for (int64_t i 0; i 8; i) { if ((!int64_array_a-IsNull(i)) (!int64_array_b-IsNull(i))) { bool comparison_result int64_array_a-Value(i) int64_array_b-Value(i); boolean_builder.UnsafeAppend(comparison_result); } else { boolean_builder.UnsafeAppendNull(); } } std::shared_ptrarrow::Array array_a_gt_b_self; ARROW_RETURN_NOT_OK(boolean_builder.Finish(array_a_gt_b_self));注意两点细节一是空值语义——任一侧为 null 时比较结果列对应位置写入 null与 Arrow 计算内核的空值传播语义一致见下文二是UnsafeAppend的前提是先前已Resize预分配了 8 个槽位属于性能优化型接口。方式二调用 compute 内核函数greaterL79-L83 展示了 Arrow 推荐的高层方式——按名称调用计算函数无需手写循环ARROW_ASSIGN_OR_RAISE(arrow::Datum compared_datum, arrow::compute::CallFunction(greater, {array_a, array_b})); auto array_a_gt_b_compute compared_datum.make_array();CallFunction(greater, {a, b})以两个Array作为输入Datum返回的Datum通过make_array()还原为布尔数组。从源码看greater内核在 cpp/src/arrow/compute/kernels/scalar_compare.cc 中注册L860-L862 定义了其文档签名L899 通过MakeCompareFunctionGreater(greater, greater_doc)完成注册L903 还用同一内核生成了less函数。函数文档明确说明其语义与空值行为Compare values for ordered inequality (x y) — A null on either side emits a null comparison result.这正是示例手写循环里UnsafeAppendNull()分支要模拟的行为。此外仓库中的单元测试 cpp/src/arrow/compute/kernels/scalar_compare_test.cc例如 L458-L462 的时间类型用例与 L571-L575 的浮点 null 用例对greater在各类数值、时间与 null 组合下的输出做了覆盖验证可作为理解该内核行为的参考。两种方式的预期结果两列数据a {1,2,3,4,5,6,7,8}、b {2,5,1,3,6,2,7,4}逐位比较a b两个布尔列结果完全一致位置aba b012false125false231true343true456false562true677false784true第三步用 Schema 与 Table::Make 组装输出表比较完成后示例构建 Schema 并把四个列合成一张表L85-L93auto schema arrow::schema({arrow::field(a, arrow::int64()), arrow::field(b, arrow::int64()), arrow::field(ab? (self written), arrow::boolean()), arrow::field(ab? (arrow), arrow::boolean())}); std::shared_ptrarrow::Table my_table arrow::Table::Make( schema, {array_a, array_b, array_a_gt_b_self, array_a_gt_b_compute});arrow::field与arrow::int64()/arrow::boolean()分别创建字段与数据类型arrow::schema把四个字段组合成 SchemaTable::Make把四个等长Array按 Schema 顺序填入。这里刻意同时保留自写比较结果与Arrow 计算比较结果两列方便直接对比两种方式的输出一致性。Table::Make会校验列数与 Schema 字段数、各列长度是否一致这也是组装阶段最常见的错误来源。第四步写出 CSV 文件L95-L101 完成最后的落盘auto csv_filename compute_and_write_output.csv; ARROW_ASSIGN_OR_RAISE(auto outstream, arrow::io::FileOutputStream::Open(csv_filename)); std::cout Writing CSV file std::endl; ARROW_RETURN_NOT_OK(arrow::csv::WriteCSV( *my_table, arrow::csv::WriteOptions::Defaults(), outstream.get()));流程是arrow::io::FileOutputStream::Open打开不存在则创建输出文件 → 传入WriteOptions::Defaults()与文件流 →WriteCSV将 Table 序列化写入。WriteCSV 的底层实现arrow::csv::WriteCSV有 Table、RecordBatch、RecordBatchReader 三种重载声明在 cpp/src/arrow/csv/writer.h 的 L46-L57。其核心实现位于 cpp/src/arrow/csv/writer.cc 的 L666-L678内部是创建 Writer → 写表 → 关闭三步Status WriteCSV(const Table table, const WriteOptions options, arrow::io::OutputStream* output) { ASSIGN_OR_RAISE(auto writer, MakeCSVWriter(output, table.schema(), options)); RETURN_NOT_OK(writer-WriteTable(table)); return writer-Close(); }其中MakeCSVWriter也在 writer.h 暴露为公开 API支持传入Schema创建增量式写入器RecordBatchWriter适合流式写出 RecordBatch 的场景。若需分批写出可以使用MakeCSVWriter后多次调用WriteTable/WriteRecordBatch最后关闭输出流。此外writer.h 头部注释L31-L39说明了 CSV 写出的格式化规则支持所有可转为StringArray/LargeStringArray的原始类型非二进制类型不加引号null 值表示为空字符串二进制类型非 null 数据全部加引号内部引号转义为双引号null 值为空且不加引号。WriteOptions 关键参数示例使用WriteOptions::Defaults()但 cpp/src/arrow/csv/options.h 的 L187-L213 展示了可调参数实际项目中常按需覆盖参数默认值说明include_headertrue是否写出首行列名batch_size1024每批处理的行数影响写入性能delimiter,字段分隔符null_string空字符串null 值的写出文本不允许含引号eol\n行结束符quoting_styleQuotingStyle::Needed引号策略另有AllValid全部加引号与None不加引号若值含引号/分隔符/换行将报错见 L179-L185例如将分隔符改为制表符、去掉表头可以这样构造选项auto options arrow::csv::WriteOptions::Defaults(); options.delimiter \t; options.include_header false;运行后的输出文件程序运行后当前目录生成compute_and_write_output.csv四列内容对应 Schemaa,b,ab? (self written),ab? (arrow) 1,2,false,false 2,5,false,false 3,1,true,true 4,3,true,true 5,6,false,false 6,2,true,true 7,7,false,false 8,4,true,true可以看到自写比较列与Arrow 计算列逐行一致直观验证了两条比较路径语义等价。延伸示例在整个文档体系中的位置本文对应的官方文档页是 docs/source/cpp/examples/compute_and_write_example.rst它与cmake_minimal_build、dataset_documentation_example、row_columnar_conversion等共同收录在 docs/source/cpp/examples/index.rst 的 Examples 目录中是官方推荐的 C 入门示例集之一。仓库中同目录下还有大量可对照学习的示例例如 row_wise_conversion_example.cc行式转换、parquet_read_write.ccParquet 读写、udf_example.cc自定义计算函数等。小结通过这一个示例可以完整掌握 Apache Arrow C 的四个核心操作用 Builder 按列构建数组、用CallFunction(greater, ...)调起矢量化计算内核区别于手写循环、用schemaTable::Make组装列式表、用WriteCSVWriteOptions写出 CSV。其中手写循环 vs 计算内核的对照设计尤其适合作为理解 Arrow列式计算、空值传播、零拷贝共享设计哲学的起点当数据规模增长时用CallFunction替代手写循环还能自然获得 Arrow 计算库的 SIMD 向量化与多线程调度能力。赞分享数据工程数据分析大数据【免费下载链接】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 实战构建数值表、计算列比较并写入 CSV 的完整示例解析Apache Arrow C 实战构建数值表、计算列比较并写入 CSV 的完整示例解析 Apache Arrow 的 C 核心库以列式内存格式 数据工程大数据序列化数据分析Apache Arrow C 示例解析用 compute 比较列数据并写出 CSV 文件Apache Arrow C 示例解析用 compute 比较列数据并写出 CSV 文件 本指南围绕 Apache Arrow 仓库中的官方 C 示例大数据数据分析数据工程序列化Apache Arrow C 官方示例全解析最小构建、Datasets、Skyhook 与行列转换实战指南Apache Arrow C 官方示例全解析最小构建、Datasets、Skyhook 与行列转换实战指南 本文以 Apache Arrow 官方 C数据工程数据分析大数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考