Arrow C++ 8.0.0解析JSON字典列表时段错误问题及解决方法
问题:使用Arrow 8.0.0解析JSON列表内字典的x值时出现段错误?
我有如下JSON文件:
{"b": [{"x": 1}, {"x": 2}, {"x": 3}]}
希望使用Arrow 8.0.0的C++代码解析该JSON中列表b内每个字典的x值,最终得到整数数组。我的当前代码如下:
#include <arrow/api.h> #include <arrow/filesystem/api.h> #include <arrow/json/api.h> #include <arrow/memory_pool.h> #include <iostream> int main() { // Copied from https://arrow.apache.org/docs/cpp/json.html#basic-usage arrow::Status st; arrow::MemoryPool* pool = arrow::default_memory_pool(); auto fs = arrow::fs::FileSystemFromUri("file:///path/to/arrow_json") .ValueOrDie(); auto file = fs->OpenInputFile("/path/to/arrow_json/test.json") .ValueOrDie(); auto read_options = arrow::json::ReadOptions::Defaults(); auto parse_options = arrow::json::ParseOptions::Defaults(); auto reader = arrow::json::TableReader::Make(pool, file, read_options, parse_options) .ValueOrDie(); auto table = reader->Read().ValueOrDie(); auto b = std::static_pointer_cast<arrow::StructArray>( table->GetColumnByName("b")->chunk(0)); std::cout << "b: " << b->ToString() << "\n"; /* b->ToString shows: b: [ -- is_valid: all not null -- child 0 type: int64 [ 1, 2, 3 ] ] */ auto x = b->GetFieldByName("x"); // this segfaults if (x) { auto val = std::static_pointer_cast<arrow::Int64Array>(x); if (val) { std::cout << "val\n"; std::cout << "val: " << val->ToString() << "\n"; } } }
为何代码在尝试访问"x"时发生段错误?该如何修复使其正常工作?
原因分析
段错误的核心原因是对Arrow数据结构的理解有误:
- 你当前把
table->GetColumnByName("b")->chunk(0)强转为StructArray是错误的。JSON中的b是数组类型(元素是结构体),所以这个chunk实际是ListArray,而非StructArray。 - 直接对错误的类型调用
GetFieldByName("x")会导致未定义行为,最终触发段错误。
从你打印的b->ToString()输出也能看出,它是一个包含子数组的结构,本质是列表类型,而非单个结构体。
修复方案
需要先将chunk转为ListArray,再获取列表中的结构体元素,最后提取结构体中的x字段:
- 把
b的chunk正确转为ListArray; - 通过列表的
values方法获取所有结构体组成的StructArray; - 从
StructArray中提取x字段对应的整数数组。
修改后的代码如下:
#include <arrow/api.h> #include <arrow/filesystem/api.h> #include <arrow/json/api.h> #include <arrow/memory_pool.h> #include <iostream> int main() { arrow::Status st; arrow::MemoryPool* pool = arrow::default_memory_pool(); auto fs = arrow::fs::FileSystemFromUri("file:///path/to/arrow_json") .ValueOrDie(); auto file = fs->OpenInputFile("/path/to/arrow_json/test.json") .ValueOrDie(); auto read_options = arrow::json::ReadOptions::Defaults(); auto parse_options = arrow::json::ParseOptions::Defaults(); auto reader = arrow::json::TableReader::Make(pool, file, read_options, parse_options) .ValueOrDie(); auto table = reader->Read().ValueOrDie(); // 正确转为ListArray(因为b是数组类型) auto b_list = std::static_pointer_cast<arrow::ListArray>( table->GetColumnByName("b")->chunk(0)); // 获取列表中所有结构体元素组成的StructArray auto struct_array = std::static_pointer_cast<arrow::StructArray>(b_list->values()); // 提取x字段对应的Int64Array auto x_array = std::static_pointer_cast<arrow::Int64Array>( struct_array->GetFieldByName("x")); // 打印验证结果 std::cout << "x values: " << x_array->ToString() << "\n"; // 遍历输出每个x值 for (int i = 0; i < x_array->length(); ++i) { std::cout << "x[" << i << "] = " << x_array->Value(i) << "\n"; } return 0; }
代码说明
ListArray::values()返回列表中所有元素组成的数组,这里每个元素是结构体,因此得到StructArray;StructArray::GetFieldByName("x")可安全获取存储所有x值的Int64Array;- 最后可通过
Value(i)方法遍历每个整数,或使用数组的其他方法处理数据。
内容的提问来源于stack exchange,提问作者GKX
相关产品推荐
相关产品推荐

