对于相同的数据集,格式等,为什么.write.partitionBy()。sortBy()。saveAsTable()产生的数据输出比.write.save小得多?

时间:2018-07-22 01:57:56

标签: scala apache-spark

在EMR上使用Spark 2.3,我正在做ETL,并使用dataframe.write.partitionyBy("column1").parquet("location")在scala中写入结果以写入临时结果。

然后我将我的临时数据读入一个新框架,并在数据集中添加另一列。我使用以下内容写出最终结果。我添加bucketBy和sortBy进行排序,以提高对“ column2”的查询的性能,该查询通常用于联接和其他过滤器。

newdataframe.write.partitionBy("column1").bucketBy(1,"column2").sortBy("column2").option("path","location").saveAsTable("tablename")

第一行给我每个分区200个部分,每个部分为770mb。第二个分区给我200个分区,每个分区192mb。

两个数据集产生相同的度量标准(第4列的总和),并且行数几乎相同(相差<0.1%)。

为什么即使一个结果具有相同的拼花格式,第二个数据集又有1个列和相同的分区列,结果却比另一个小得多?

感谢任何帮助。

1 个答案:

答案 0 :(得分:4)

由于您是在镶木地板中写入数据,因此在对数据进行排序的同时进行保存,镶木地板字典将开始编码。

面向木地板列的存储确实使用字典进行长度编码。这意味着我们可以说有很长的重复单词序列,例如

spark spark spark ... 1000次。现在,不用存储它,您可以创建一个字典

spark --> 1

并将火花序列表示为:1,1000。

这大大减少了空间。

但是,如果在row group中(数据的逻辑水平划分为行。没有保证行组的物理结构。行组由数据集中每个列的列块组成。)不存在重复的数据,因此不会进行任何字典优化,导致拼花文件的大小更大。

在您的情况下,由于您正在对数据进行排序,因此所有具有相同值的数据都将合并到一个行组中,并且镶木地板将能够进行字典优化。

Parquet将压缩逻辑存储在页脚中。您可以使用以下代码在两种不同情况下打印页脚,并比较编码和压缩情况。

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.{Path, FileSystem}
import org.apache.parquet.format.converter.ParquetMetadataConverter
import org.apache.parquet.hadoop.ParquetFileReader

object ParquetPrintFooter {

  def main (args: Array[String]) : Unit = {
  val config = new Configuration()
  val filePath = new Path("/data/test.par");
  val fileStatus = 
  FileSystem.get(config).getFileStatus(filePath)
  val parquetMetadata = 
  ParquetFileReader.readFooter(config, fileStatus, 
  ParquetMetadataConverter.NO_FILTER)
  println(parquetMetadata)
}

}