为什么Spark DataFrame创建错误数量的分区?

时间:2017-07-03 05:23:48

标签: scala apache-spark apache-spark-sql parquet

我有一个包含2列的火花数据框 - #!/bin/bash for e in /mapr/datalake/rawfiles/P20170626005/* do mv "$e" `echo $e | sed -e 's/\(.*\)P20170626\(.*\)/\1P20170626005\2/g'` done col1

col2

当我以scala> val df = List((1, "a")).toDF("col1", "col2") df: org.apache.spark.sql.DataFrame = [col1: int, col2: string] 格式在磁盘上写df时,要写入与parquet中唯一值的数量相等的文件数量的所有数据,我会col1使用repartition,像这样:

col1

上面的代码只在文件系统中生成一个文件。但是,随机播放操作的次数变为200次。

enter image description here

我无法理解,如果scala> df.repartition(col("col1")).write.partitionBy("col1").parquet("file") 只包含一个值,即col1那么为什么它会在1中创建200个分区?

2 个答案:

答案 0 :(得分:4)

默认情况下,

repartition(columnName)创建200个分区(更具体的spark.sql.shuffle.partitions分区),无论有多少col1个唯一值。如果col1只有1个唯一值,则199个分区为空。另一方面,如果您拥有超过200个col1的唯一值,则每个分区将有多个col1值。

如果您只想要1个分区,那么您可以repartition(1,col("col1"))coalesce(1)。但并非coalescecoalesce我的代码中可能会进一步提升并行性(请参阅How to prevent Spark optimization

的意义上表现不一样

如果您想查看分区的内容,我已经为此制作了两种方法:

// calculates record count per partition
def inspectPartitions(df: DataFrame) = {
    import df.sqlContext.implicits._
    df.rdd.mapPartitions(partIt => {
       Iterator(partIt.toSeq.size)
    }
    ).toDF("record_count")
}

// inspects how a given key is distributed accross the partition of a dataframe
def inspectPartitions(df: DataFrame, key: String) = {
    import df.sqlContext.implicits._
    df.rdd.mapPartitions(partIt => {
      val part = partIt.toSet
      val partSize = part.size
        val partKeys = part.map(r => r.getAs[Any](key).toString.trim)
        val partKeyStr = partKeys.mkString(", ")
        val partKeyCount = partKeys.size
       Iterator((partKeys.toArray,partSize))
    }
    ).toDF("partitions","record_count")
}

现在你可以,例如像这样检查你的数据帧:

inspectPartitions(df.repartition(col("col1"),"col1")
.where($"record_count">0)
.show

答案 1 :(得分:2)

在Spark SQL shuffle世界中,默认的shuffle分区数为200,由spark.sql.shuffle.partitions

控制