首页 > 解决方案 > Parquet 压缩性能分组与平面数据

问题描述

无法从网上得到直接的答案。考虑以下数据场景:我有包含 user_id 和用户活动时间戳的数据:

val bigData = Seq( ( "id3",12),
                 ("id1",55),
                 ("id1",59),
                 ("id1",50),
                 ("id2",51),
                 ("id3",52),
                 ("id2",53),
                 ("id1",54),
              ("id2", 34)).toDF("user_id", "ts")

所以原始的 DataFrame 看起来像这样:

+-------+---+
|user_id| ts|
+-------+---+
|    id3| 12|
|    id1| 55|
|    id1| 59|
|    id1| 50|
|    id2| 51|
|    id3| 52|
|    id2| 53|
|    id1| 54|
|    id2| 34|
+-------+---+

例如,这就是我将写入 HDFS\S3 的内容。

但是我无法保存按用户分组的数据,例如:

bigData.groupBy("user_id").agg(collect_list("ts") as "ts")

导致:

+-------+----------------+
|user_id|              ts|
+-------+----------------+
|    id3|        [12, 52]|
|    id1|[55, 59, 50, 54]|
|    id2|    [51, 53, 34]|
+-------+----------------+

对于哪种方法可以在文件系统上获得更好的存储/压缩,我可以得到一个决定性的答案。分组方法看起来(直观地)更好的存储/压缩方式。

任何人都知道是否有绝对的方法或知道关于这个主题的任何基准或文章?

标签: apache-sparkcompressionbigdataparquet

解决方案


让我们考虑以扁平结构存储数据的第一种情况。如果您对数据进行排序,id那么相同的 id 将进入相同的分区。这将导致Parquet 字典压缩,从而减小大小。

此外,如果您ts是有界的,那么镶木地板格式会保留基础并创建偏移量。

例如

50 51 52 60 are the ts
Parquet saves : base: 50, offset: 0, 1, 2, 8

如果偏移量可以用 2 个字节表示,这可能会节省更多空间。

其他格式也是有效的。但唯一的问题是,由于 parquet 是一种列格式,列值越大,parquet 将为其余列值创建填充

例如

ts
----
[20], 
[20,40,60,70,80]

parquet 将为 20 创建填充并将其保持为[20,40,60,70,80].

我建议您对数据集进行各种实验,测量大小并检查镶木地板页脚。您将深入了解 parquet 如何为您的应用程序存储数据。问题是数据大小将取决于基础数据,因此我们可能无法得到确凿的答案。


推荐阅读