提问者:小点点

重新分区parquet-mr生成parquets与pyarrow/parquet-cpp增加文件大小x30?


使用AWSFirehose,我正在将传入的记录转换为parket。在一个示例中,我有150k相同的记录进入Firehose,并且一个30kb的parket被写入s3。由于Firehose如何分区数据,我们有一个辅助进程(由s3 put事件触发的lambda)读取parket并根据事件本身中的日期对其进行重新分区。在这个重新分区过程之后,30kb的文件大小跳转到900kb。

检查两个镶木地板文件-

  • meta不会改变
  • 数据不会改变
  • 他们都使用SNAPPY压缩
  • 火管拼花由parquet-mr创建,py箭头生成的拼花由parquet-cpp创建
  • pyarrow生成的镶木地板有额外的熊猫标头

完整的重新分区过程-

import pyarrow.parquet as pq

tmp_file = f'{TMP_DIR}/{rand_string()}'
s3_client.download_file(firehose_bucket, key, tmp_file)

pq_table = pq.read_table(tmp_file)

pq.write_to_dataset(
    pq_table,
    local_partitioned_dir,
    partition_cols=['year', 'month', 'day', 'hour'],
    use_deprecated_int96_timestamps=True
)

我想会有一些大小的变化,但我惊讶地发现如此大的差异。鉴于我所描述的过程,是什么导致源拼花地板从30kb变为900kb?


共1个答案

匿名用户

Parquet使用不同的列编码来非常有效地存储低熵数据。例如:

    null

使用上述示例的3到5个值,节省的费用并不显著,但是值越多,收益就越大。由于您有150k相同的记录,因此收益将是巨大的,因为使用RLE字典编码,每个列值只需存储一次,然后标记为重复150k次。

但是,pyarrow似乎没有使用这些节省空间的编码。您可以通过使用parquet-tools meta查看两个文件的元数据来确认这一点。这是一个示例输出:

file schema: hive_schema 
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id:          OPTIONAL INT32 R:0 D:1
name:        OPTIONAL BINARY O:UTF8 R:0 D:1

row group 1: RC:61 TS:214 OFFSET:4 
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id:           INT32 UNCOMPRESSED DO:0 FPO:4 SZ:107/107/1.00 VC:61 ENC:BIT_PACKED,RLE,PLAIN_DICTIONARY ST:[min: 1, max: 5, num_nulls: 0]
name:         BINARY UNCOMPRESSED DO:0 FPO:111 SZ:107/107/1.00 VC:61 ENC:BIT_PACKED,RLE,PLAIN_DICTIONARY ST:[min: Los Angeles, max: San Francisco, num_nulls: 0]

编码显示为ENC:BIT_PACKED, RLE,PLAIN_DICTIONARY