为什么分区的 parquet 文件占用更大的磁盘 space?

Why partitioned parquet files consume larger disk space?

我正在使用 python 和 pyarrow 学习镶木地板文件。 Parquet 在压缩和最小化磁盘方面表现出色 space。我的数据集是 190MB 的 csv 文件,当另存为 snappy-compressed parquet 文件时,它最终会变成一个 3MB 的文件。

然而,当我将我的数据集保存为分区文件时,它们会产生更大的组合大小 (61MB)。

这是我要保存的示例数据集:

listing_id |     date     | gender | price
-------------------------------------------
     a     |  2019-01-01  |   M    |   100
     b     |  2019-01-02  |   M    |   100
     c     |  2019-01-03  |   F    |   200
     d     |  2019-01-04  |   F    |   200

当我按日期(300 多个唯一值)分区时,分区文件的总大小为 61MB。每个文件的大小为 168.2kB。 当我按性别(2 个唯一值)分区时,分区后的文件合并后只有 3MB。

我想知道 parquet 是否有任何最小文件大小,以便许多小文件加在一起占用更大的磁盘空间space?

我的环境:

- OS: Ubuntu 18.04
- Language: Python
- Library: pyarrow, pandas

我的数据集来源:

https://www.kaggle.com/brittabettendorf/berlin-airbnb-data

# I am using calendar_summary.csv as my data from a group of datasets in that link above

我保存为 parquet 文件的代码:

# write to dataset using parquet
df = pd.read_csv('./calendar_summary.csv')
table = pyarrow.Table.from_pandas(df)
pyarrow.parquet.write_table(table=table, where='./calendar_summary_write_table.parquet')

# parquet filesize
parquet_method1_filesize = os.path.getsize('./calendar_summary_write_table.parquet') / 1000
print('parquet_method1_filesize: %i kB' % parquet_method1_filesize)

我的代码保存为 partitioned parquet 文件:

# write to dataset using parquet (partitioned)
df = pd.read_csv('./calendar_summary.csv')
table = pyarrow.Table.from_pandas(df)
pyarrow.parquet.write_to_dataset(
    table=table, 
    root_path='./calendar_summary/', 
    partition_cols=['date'])

# parquet filesize
import os
print(os.popen('du -sh ./calendar_summary/').read())

没有最小文件大小,但存储页脚会产生开销,并且会浪费通过编码和压缩进行优化的机会。各种编码和压缩建立在数据具有一定程度的自相似性的思想之上,可以通过引用回更早的相似事件来利用这种自相似性。当您将数据拆分为多个文件时,每个文件都需要一个单独的 "initial data point" 以便后续文件可以引用,因此磁盘使用率会上升。 (请注意,此措辞过于简单化,以避免必须专门研究用于保存 space 的各种技术,但请参阅 中的一些示例。)

另一个可能对 Parquet 文件的大小产生巨大影响的因素是数据插入的顺序。与随机排序的列相比,排序列的存储效率要高得多。通过对数据进行分区,您可能会无意中更改其排序顺序。另一种可能性是,您根据数据排序所依据的属性对数据进行分区,这在存储在单个文件中时可以节省大量 space ,而将数据拆分为多个文件会失去这种机会。最后,您必须记住,Parquet 并未针对存储几千字节的数据进行优化,而是针对几兆字节或千兆字节(在单个文件中)或几拍字节(在多个文件中)进行了优化。

如果您想检查数据在 Parquet 文件中的存储方式,Parquet 的 Java 实现包括 parquet-tools 实用程序,它提供了多个命令。请参阅其 documentation page 以了解构建和入门。各个命令的更详细描述由 parquet-tools 自己打印。您最感兴趣的命令可能是 metadump.