Parquet按行分块添加dummy列后,Snappy压缩能否缩减额外数据?
问题
我正在处理一个含1亿行的DataFrame,希望将其划分为100个各含100万行的Parquet文件,无需按特定列值分区,仅需按行分块。
已知可通过添加“dummy列”并传入partition_cols参数实现,代码如下:
data_size = len(data) partition_size = 1_000_000 n_partitions, remainder = divmod(data_size, partition_size) data["partition_id"] = np.concatenate([ np.repeat(list(range(n_partitions)), partition_size), np.repeat(n_partitions + 1, remainder), ]) data.to_parquet("out", partition_cols=["partition_id"])
但我担心写入额外1亿个64位整数会造成浪费。Parquet通常采用Snappy等压缩算法,而该列是长重复整数序列,理论上压缩效果极佳。不过我不清楚Parquet文件格式与底层Arrow数组格式和压缩算法的交互,想了解使用Snappy时,这些额外整数是否会被压缩到极少字节,还是会显著增加数据集体积?
回答
首先可以明确:这种重复序列的dummy列用Snappy压缩后,几乎不会增加额外的存储体积,完全不用担心浪费问题。
原因可以从Parquet+Arrow的存储逻辑和Snappy的特性两方面拆解:
- Arrow数组的编码优化:Arrow会先对这种高度重复的整数序列做字典编码(Dictionary Encoding)——把重复的整数(比如0到100)作为字典键,然后用对应的索引值替代原数据。原本1亿个64位整数,会被转换成101个唯一键(0到100)加上1亿个极小的索引值(比如只用1字节就能存下0-100的索引),这一步已经把数据量大幅压缩。
- Snappy的二次压缩:Snappy针对重复/冗余数据的压缩效率极高,经过字典编码后的索引序列是连续重复的块(100万个0,接着100万个1,以此类推),Snappy能把这类序列压缩到极致,最终这个dummy列的实际存储大小可能只有几KB级别,相比1亿行的原始DataFrame可以忽略不计。
另外,还有个更直接的替代方案可以完全避免添加dummy列:直接按行切片写入,逻辑更直接且无额外存储开销,适合单纯按行分块的场景:
partition_size = 1_000_000 for i in range(0, len(data), partition_size): chunk = data.iloc[i:i+partition_size] chunk.to_parquet(f"out/part_{i//partition_size}.parquet")
内容的提问来源于stack exchange,提问作者shadowtalker
相关产品推荐
相关产品推荐

