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

C++操作Parquet:如何写入Map嵌套类型?

解决Parquet C++中Map<Integer, String>类型的定义与写入问题

我之前也踩过Parquet Map类型的坑,尤其是C++这边官方文档和示例确实偏少,我来给你一步步讲清楚怎么实现Map<Integer, String>类型的列定义和数据写入。

首先得明确核心点:Parquet的Map逻辑类型不是通过PrimitiveNode定义的,它本质是一个符合特定规范的嵌套Group结构——底层是一个REPEATED的Group,内部包含key(必填、无重复)和value两个字段,同时要给这个Group标记Map逻辑类型。你之前用PrimitiveNode的写法是完全错误的,这也是为什么你会对最后一个原始类型参数存疑。

一、正确定义Map列的Schema

我们要构建的是Map<Integer, String>,对应Parquet的类型映射:

  • 键:INT32(对应C++的int),重复类型REQUIRED
  • 值:BYTE_ARRAY + UTF8逻辑类型(对应C++的std::string),重复类型REQUIRED(如果允许值为null可以改成OPTIONAL)

以下是代码示例:

#include <parquet/schema.h>
#include <parquet/logical_type.h>

// 构建Map的key字段:INT32类型,必填
auto map_key = parquet::schema::PrimitiveNode::Make(
    "key", parquet::Repetition::REQUIRED, parquet::Type::INT32, parquet::ConvertedType::NONE);

// 构建Map的value字段:BYTE_ARRAY(UTF8字符串),必填
auto map_value = parquet::schema::PrimitiveNode::Make(
    "value", parquet::Repetition::REQUIRED, parquet::Type::BYTE_ARRAY, parquet::ConvertedType::UTF8);

// 构建Map的Group节点:重复类型,标记为Map逻辑类型
std::vector<std::shared_ptr<parquet::schema::Node>> map_fields;
map_fields.push_back(map_key);
map_fields.push_back(map_value);

auto map_column = parquet::schema::GroupNode::Make(
    "my_map_column",  // 自定义列名
    parquet::Repetition::REPEATED,  // Map是多个键值对的集合,必须设为REPEATED
    map_fields,
    parquet::LogicalType::Map());  // 标记该Group为Map逻辑类型

// 构建整个Schema(可添加其他字段)
std::vector<std::shared_ptr<parquet::schema::Node>> schema_fields;
schema_fields.push_back(map_column);
// 示例:添加一个普通INT64类型的id字段
// schema_fields.push_back(parquet::schema::PrimitiveNode::Make("id", parquet::Repetition::REQUIRED, parquet::Type::INT64));

auto schema = parquet::schema::GroupNode::Make("root_schema", parquet::Repetition::REQUIRED, schema_fields);

二、写入Map类型的数据

写入时需要使用GroupWriter来操作这个嵌套的Map结构,步骤如下:

  1. 创建Parquet FileWriter
  2. 获取对应的RowGroupWriter
  3. 获取Map列的GroupWriter
  4. 遍历每一行数据,对每个Map:
    • 遍历键值对,每个键值对对应一次StartGroup() → 写入key和value → EndGroup()

完整写入示例:

#include <parquet/file_writer.h>
#include <parquet/column_writer.h>
#include <map>
#include <string>

int main() {
    // 先按照上面的代码构建好schema

    // 创建FileWriter,使用SNAPPY压缩
    parquet::WriterProperties::Builder props_builder;
    auto props = props_builder.build();
    std::unique_ptr<parquet::FileWriter> file_writer = parquet::ParquetFileWriter::Open(
        "map_example.parquet", parquet::Compression::SNAPPY, schema, props);

    // 创建RowGroupWriter
    std::unique_ptr<parquet::RowGroupWriter> row_group_writer = file_writer->AppendRowGroup();

    // 获取Map列的GroupWriter(假设Map列是第0列)
    auto map_group_writer = row_group_writer->Column(0)->AsGroupWriter();

    // 准备测试数据:一行中的Map内容
    std::map<int, std::string> test_map = {{1, "apple"}, {2, "banana"}, {3, "cherry"}};

    // 写入这个Map的所有键值对
    for (const auto& kv : test_map) {
        // 开始一个键值对的Group实例
        map_group_writer->StartGroup();

        // 写入key:获取key字段的PrimitiveWriter
        auto key_writer = map_group_writer->Column(0)->AsPrimitiveWriter<int32_t>();
        key_writer->WriteBatch(1, nullptr, nullptr, &kv.first);

        // 写入value:将std::string转为Parquet ByteArray后写入
        auto value_writer = map_group_writer->Column(1)->AsPrimitiveWriter<parquet::ByteArray>();
        parquet::ByteArray value_bytes(kv.second.data(), kv.second.size());
        value_writer->WriteBatch(1, nullptr, nullptr, &value_bytes);

        // 结束当前键值对的Group实例
        map_group_writer->EndGroup();
    }

    // 完成RowGroup和File的写入
    row_group_writer->Close();
    file_writer->Close();

    return 0;
}

三、关键注意事项

  • Map的Group必须设为REPEATED:因为一个Map包含多个键值对,每个键值对对应一个Group实例
  • key字段必须是REQUIRED且唯一:Parquet规范要求Map的键不能重复,写入时要自行保证这一点
  • String类型必须用BYTE_ARRAY + UTF8逻辑类型:C++ API中没有直接的STRING原始类型,需要通过这种方式定义字符串
  • 每个键值对都要单独调用StartGroup()和EndGroup():这是Parquet Map结构的底层要求,每个键值对都是Map Group的一个重复元素

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 21:34:06