Parquet 压缩性能分组与平面数据

Parquet compression performance grouped vs flat data

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

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]|
+-------+----------------+

我可以得到关于哪种方法在文件系统上更好 storage/compression 的决定性答案。分组方法看起来(直观地)更好 storage/comperssion 明智。

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

让我们考虑第一种情况,其中数据存储在平面结构中。如果您对数据进行 w.r.r 和 id 排序,那么相同的 ID 将转到相同的分区。这将导致 Parquet dictionary compression 从而减小大小。

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

例如

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

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

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

例如

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

parquet 将为 20 创建填充并将其保持与 [20,40,60,70,80] 相同的大小。

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