Parquet行组大小含义解析及合并优化技术咨询
背景与需求
- 刚接触Parquet格式,Apache官方推荐Row-Group大小为512MB-1GB,部分资料显示默认值为128MB
- 有一批将在AWS Glue PySpark中处理的Parquet文件,源文件Row-Group极小(例如一个85MB的snappy压缩文件,包含1115个Row-Group,每个约500KB,总未压缩大小约500MB)
- 希望合并Row-Group以提升处理效率,假设Spark会逐Row-Group读取,过多小Row-Group会增加IO操作
核心问题解答
子问题1:pqrs报告的Row-Group大小是否为未压缩内存大小?
是的,pqrs工具展示的Row-Group大小为未压缩的内存大小,磁盘上的实际文件大小是压缩后的结果,因此会与计算的总未压缩大小存在差异。你提到的文件总未压缩大小约500MB,经snappy压缩后磁盘大小为85MB,符合snappy通常1:3~1:6的压缩比范围。
子问题2:官方推荐的Row-Group大小指未压缩还是压缩后?
Apache官方推荐的512MB-1GB(或默认128MB)Row-Group大小,指的是未压缩的内存大小,与pqrs报告的数值直接对应。选择该范围是为了平衡IO效率与内存占用:过大的Row-Group会增加内存压力,过小则会触发频繁的IO请求,降低处理效率。
Spark读取Row-Group的假设验证
你的假设正确:Spark读取Parquet时以Row-Group为基本IO单位,过多小Row-Group会导致大量小IO请求,增加磁盘开销与任务调度成本,合并为合适大小的Row-Group可有效提升处理效率。
合并Row-Group的代码优化与BatchSize设置
你当前使用的PyArrow合并代码如下:
import pyarrow.dataset as ds import pyarrow.parquet as pq def compact_parquet_in_batches(infile, outfile, batchsize): parquet_file = pq.ParquetFile(infile) ds.write_dataset( parquet_file.iter_batches(batch_size=batchsize), outfile, schema=RSCHEMA, format='parquet' )
这里的核心问题是:iter_batches的batch_size是记录数,但ds.write_dataset写入Parquet时,会受PyArrow默认的未压缩Row-Group大小限制(默认128MB),仅靠记录数无法精准控制Row-Group大小。
正确的配置方式
要精准控制Row-Group大小,需在写入时直接指定未压缩的Row-Group字节数,而非仅依赖记录数:
方式1:使用ParquetWriter直接控制
import pyarrow.parquet as pq def compact_parquet(infile, outfile, target_row_group_size): parquet_file = pq.ParquetFile(infile) schema = parquet_file.schema # 直接指定未压缩Row-Group大小(字节),例如128MB:128 * 1024 * 1024 writer = pq.ParquetWriter( outfile, schema=schema, compression='snappy', row_group_size=target_row_group_size ) for batch in parquet_file.iter_batches(): writer.write_batch(batch) writer.close()
方式2:在ds.write_dataset中配置写入参数
import pyarrow.dataset as ds import pyarrow.parquet as pq def compact_parquet_in_batches(infile, outfile, target_row_group_size): parquet_file = pq.ParquetFile(infile) write_options = ds.ParquetWriteOptions( compression='snappy', row_group_size=target_row_group_size ) ds.write_dataset( parquet_file.iter_batches(), outfile, schema=parquet_file.schema, format='parquet', write_options=write_options )
为何设置60000条记录生成了2个Row-Group?
因为PyArrow默认的未压缩Row-Group大小为128MB,当写入的数据累积到128MB未压缩大小后,会自动生成一个Row-Group。你设置的60000条记录对应的未压缩大小超过了128MB,因此被拆分为两个Row-Group(第一个达到128MB,剩余数据作为第二个)。
内容的提问来源于stack exchange,提问作者teejay

