You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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字段:

  1. 把b的chunk正确转为ListArray;
  2. 通过列表的values方法获取所有结构体组成的StructArray;
  3. 从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 10:36:23