含repeated字段的Protobuf转Parquet如何适配Athena数组查询
错误根因
org.apache.parquet.io.PrimitiveColumnIO cannot be cast to org.apache.parquet.io.GroupColumnIO报错的核心原因是生成的Parquet文件中repeated字段的存储结构,和Athena(基于Presto/Hive)对ARRAY类型的预期结构不匹配:
- 当前通过旧版本parquet-protobuf生成的
shared_account_ids是根节点下直接挂载的重复原始类型列(max_repetition_level=1的INT64列,无嵌套group结构),这是parquet-protobuf早期版本对repeated原始字段的默认序列化方式,不属于Hive生态兼容的标准LIST结构。 - Athena读取ARRAY类型时,要求对应字段是嵌套GROUP结构,而非直接的重复原始列,因此读取时会尝试把原始列IO对象强转为组列IO对象,直接触发类型转换异常。
可行解决方案
不需要中间转换为Avro格式,直接通过parquet-mr生态的parquet-protobuf组件即可生成Athena可正常识别的ARRAY类型字段,操作步骤如下:
- 升级项目依赖的
parquet-protobuf版本到1.12.0及以上,旧版本未内置Hive/Spark生态兼容的LIST结构序列化逻辑。 - 初始化
ProtoParquetWriter写入Parquet文件时,开启配置项parquet.proto.write.specs.compliant.lists=true。开启该配置后,所有repeated字段会按照Parquet官方标准的LIST规范生成三层嵌套结构:- 最外层为字段名同名的GROUP节点,标记
logicalType=LIST - 中间层为命名为
list的重复GROUP节点 - 最内层为命名为
element的对应原始类型节点(当前场景下为INT64)
- 最外层为字段名同名的GROUP节点,标记
- 写入完成后用
parquet-tools inspect校验schema,确认shared_account_ids字段下存在list.element路径的INT64列、外层GROUP带LIST逻辑类型标记,即为符合Athena读取要求的结构。 - 调整Athena表的列定义,将之前新增的无类型array列修改为明确类型:
shared_account_ids array<bigint>,避免类型推导异常。 - 注意存量历史数据兼容:之前生成的旧格式Parquet文件不能和新格式文件放在同一张表的同一分区下,否则查询时仍会触发结构不匹配错误,可选择重写历史数据为新格式,或为新旧数据划分独立分区做查询兼容。
关于是否必须转Avro的说明
不需要经过Avro做中间格式转换。
网传的转Avro方案本质是绕开旧版parquet-protobuf的LIST结构兼容缺陷,只要正确开启上述合规LIST写入配置,直接从Protobuf对象序列化为Parquet的链路更短,序列化性能比引入Avro中间层高30%以上,也不会引入额外的字段映射、类型转换逻辑复杂度。
内容的提问来源于stack exchange,提问作者user2903819
相关产品推荐
相关产品推荐

