在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个列和相同的分区列,结果却比另一个小得多?
感谢任何帮助。
答案 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)
}
}