Spark SQL 加入空数据集会导致输出文件变大
Spark SQL join with empty dataset results in larger output file size
我 运行 遇到一个问题,在这个问题中显然在 Spark table 中执行带有空 table 的完全外部连接导致文件大小比简单地 [=33= 大得多] 在不进行连接的情况下从其他数据集中获取列。
基本上,我有两个数据集,一个很大,另一个是空的。我浏览并 select 编辑了大型数据集中的几乎所有列,并将其完全外部连接到空数据集中。然后,我将生成的数据集写入 snappy-compressed parquet(我也尝试过使用 snappy-compressed orc)。或者,我只是 select 编辑了大型数据集中的相同列,然后将生成的数据集保存为上面的 snappy-compressed parquet(或 orc)。文件大小截然不同,因为来自空数据集连接的文件几乎是简单 select 文件的五倍。
我已经在许多不同的数据集上进行了尝试,并得到了相同的结果。在看数据:
- 输出行数相同(通过读取输出数据集并进行计数,使用 spark-shell 验证)
- 模式相同(使用 spark-shell、parquet-tools 和 orc-tools 验证)
- 抽查数据看起来一样,我在两种输出类型中都没有看到任何异常数据
- 我明确保存了所有具有相同、活泼、压缩的文件,并且输出文件由 Spark
赋予了“.snappy.parquet”扩展名
我知道用空 table 进行连接实际上毫无意义(我这样做是作为一些通用代码的一部分,这些代码总是执行完整的外部连接,有时会遇到空数据集)。而且,我已经更新了我的代码,所以它不再执行此操作,因此问题已解决。
不过,我想了解为什么/如何发生这种情况。所以我的问题是——为什么 Spark SQL 加入一个空数据集会导致更大的文件大小? And/or 任何有关如何弄清楚是什么导致生成的 parquet 文件如此之大的想法也会有所帮助。
在遇到其他几种情况后,在 方式 数据处理中看似微小的差异导致文件大小存在巨大差异(对于看似完全相同的数据),我终于想通了这个出来了。
这里的关键是了解 parquet(或 orc)如何使用可能复杂的格式(例如字典编码、运行-长度编码等)对数据进行编码。这些格式利用数据冗余来缩小文件大小,即,如果您的数据包含许多相似值,则文件大小将小于许多不同值的文件大小。
在连接空数据集的情况下,重要的一点是,当 spark 进行连接时,它会在连接列上进行分区。因此,即使数据集为空,进行连接也可能会改变数据的分区方式。
在我的例子中,加入一个空数据集将分区从每个分区中许多相似记录分组在一起的分区更改为每个分区中许多不同记录分组的分区。然后,当这些分区被写出时,许多相似或不相似的记录被放在每个文件中。当分区有相似的记录时,parquet的编码非常高效,文件体积小;当分区不同时,parquet 的编码效率不高,并且文件大小更大——即使数据总体上完全相同。
如上所述,我们 运行 进入其他几个出现相同问题的实例 -- 我们将更改处理的一个方面,并获得相同的输出数据,但文件大小可能是大四倍。有助于解决这个问题的一件事是使用 parquet-tools
查看低级文件统计信息。
我 运行 遇到一个问题,在这个问题中显然在 Spark table 中执行带有空 table 的完全外部连接导致文件大小比简单地 [=33= 大得多] 在不进行连接的情况下从其他数据集中获取列。
基本上,我有两个数据集,一个很大,另一个是空的。我浏览并 select 编辑了大型数据集中的几乎所有列,并将其完全外部连接到空数据集中。然后,我将生成的数据集写入 snappy-compressed parquet(我也尝试过使用 snappy-compressed orc)。或者,我只是 select 编辑了大型数据集中的相同列,然后将生成的数据集保存为上面的 snappy-compressed parquet(或 orc)。文件大小截然不同,因为来自空数据集连接的文件几乎是简单 select 文件的五倍。
我已经在许多不同的数据集上进行了尝试,并得到了相同的结果。在看数据:
- 输出行数相同(通过读取输出数据集并进行计数,使用 spark-shell 验证)
- 模式相同(使用 spark-shell、parquet-tools 和 orc-tools 验证)
- 抽查数据看起来一样,我在两种输出类型中都没有看到任何异常数据
- 我明确保存了所有具有相同、活泼、压缩的文件,并且输出文件由 Spark 赋予了“.snappy.parquet”扩展名
我知道用空 table 进行连接实际上毫无意义(我这样做是作为一些通用代码的一部分,这些代码总是执行完整的外部连接,有时会遇到空数据集)。而且,我已经更新了我的代码,所以它不再执行此操作,因此问题已解决。
不过,我想了解为什么/如何发生这种情况。所以我的问题是——为什么 Spark SQL 加入一个空数据集会导致更大的文件大小? And/or 任何有关如何弄清楚是什么导致生成的 parquet 文件如此之大的想法也会有所帮助。
在遇到其他几种情况后,在 方式 数据处理中看似微小的差异导致文件大小存在巨大差异(对于看似完全相同的数据),我终于想通了这个出来了。
这里的关键是了解 parquet(或 orc)如何使用可能复杂的格式(例如字典编码、运行-长度编码等)对数据进行编码。这些格式利用数据冗余来缩小文件大小,即,如果您的数据包含许多相似值,则文件大小将小于许多不同值的文件大小。
在连接空数据集的情况下,重要的一点是,当 spark 进行连接时,它会在连接列上进行分区。因此,即使数据集为空,进行连接也可能会改变数据的分区方式。
在我的例子中,加入一个空数据集将分区从每个分区中许多相似记录分组在一起的分区更改为每个分区中许多不同记录分组的分区。然后,当这些分区被写出时,许多相似或不相似的记录被放在每个文件中。当分区有相似的记录时,parquet的编码非常高效,文件体积小;当分区不同时,parquet 的编码效率不高,并且文件大小更大——即使数据总体上完全相同。
如上所述,我们 运行 进入其他几个出现相同问题的实例 -- 我们将更改处理的一个方面,并获得相同的输出数据,但文件大小可能是大四倍。有助于解决这个问题的一件事是使用 parquet-tools
查看低级文件统计信息。