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

使用Arrow Dataset C++读取Parquet文件时遇std::bad_alloc错误求助

问题解决:C++读取大Parquet文件子集的内存错误与替代方案

一、std::bad_alloc错误排查与解决

你遇到的std::bad_alloc大概率和dict_columns的默认行为有关。默认情况下,ParquetFileFormat的reader_options会尝试预加载所有字典列的完整字典,如果你的10GB Parquet里有大量高基数的字典列,这会瞬间占用巨量内存,直接触发内存分配失败。

解决步骤:

  1. 显式指定需要加载的字典列,避免默认加载全部:
// 初始化format时指定仅加载目标字典列
auto format = std::make_shared<ParquetFileFormat>();
format->reader_options.dict_columns = {"目标字典列1", "目标字典列2"};
  1. 如果不需要字典解码,直接禁用字典加载:
format->reader_options.use_dictionary = false;
  1. 补全FileSystem初始化:你当前代码中fs是空指针,这会导致内部逻辑异常,需先初始化本地文件系统:
std::shared_ptr<FileSystem> fs = LocalFileSystem::Make();
  1. 限制扫描范围,减少元数据加载压力:
ds::FileSystemFactoryOptions options;
// 仅扫描目录下的.parquet文件,避免无关文件干扰
options.file_extension_whitelist = {".parquet"};

二、不使用Arrow Dataset的替代方案

如果不想依赖Arrow Dataset,直接用Parquet C++ API实现过滤扫描也能达到目的,核心是通过列投影和行过滤只加载必要数据:

方案1:直接使用Parquet Reader API做精准过滤

#include <parquet/arrow/reader.h>
#include <parquet/filter.h>

// 打开目标Parquet文件
std::unique_ptr<parquet::arrow::FileReader> reader;
PARQUET_THROW_NOT_OK(parquet::arrow::OpenFile("C:/parquet_data/your_file.parquet", fs, &reader));

// 设置列投影:仅读取需要的列(用列索引指定)
std::vector<int> column_indices = {0, 2, 3}; // 替换为你的目标列索引
PARQUET_THROW_NOT_OK(reader->SetColumnIndices(column_indices));

// 设置行过滤条件:例如过滤某列值大于100的行
auto filter = parquet::Filter::Gt("target_column", 100); // 替换为你的过滤规则
PARQUET_THROW_NOT_OK(reader->SetFilter(filter));

// 读取过滤后的数据到Arrow Table
std::shared_ptr<arrow::Table> table;
PARQUET_THROW_NOT_OK(reader->ReadTable(&table));

方案2:分块读取行组,逐块处理

如果文件过大,单次读取内存压力仍高,可以按行组分块读取,逐块过滤处理:

int num_row_groups = reader->num_row_groups();
for (int i = 0; i < num_row_groups; ++i) {
  std::shared_ptr<arrow::Table> chunk;
  // 读取单个行组数据
  PARQUET_THROW_NOT_OK(reader->ReadRowGroup(i, &chunk));
  // 对当前行组应用过滤逻辑(使用Arrow Compute API)
  auto filtered_chunk = arrow::compute::Filter(
    chunk, 
    arrow::compute::Greater(chunk->GetColumnByName("target_column"), arrow::Scalar(100))
  ).ValueOrDie();
  // 处理过滤后的chunk(如写入结果文件、计算统计值等)
}

这种方式内存占用可控,每次仅处理一个行组的数据,适合超大型Parquet文件。


内容的提问来源于stack exchange,提问作者what_is_ads

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 21:05:13