为什么Spark总是将相同数量的文件写入HDFS?

时间:2018-09-18 07:02:13

标签: apache-spark-sql hdfs spark-streaming

我有一个用Scala编写的Spark流媒体应用程序,运行在CDH中。该应用程序从Kafka读取数据,并将数据写入HDFS。在将数据写入HDFS之前,我执行partitionBy,因此将数据写入分区。每个分区在写入时会获得3个文件。我还使用coalesce来控制数据的分区数量。我的期望是,由coalesce命令设置的分区数将设置HDFS输出目录中的文件数,但是尽管coalesce命令设置的分区数仍为3。我尝试使用3个执行程序和6个执行程序运行,但是每个分区中的文件数量仍然是3。<​​/ p>

这是我将数据写入HDFS的方式:

//Some code
val ssc = new StreamingContext(sc, Seconds(1))
val stream = KafkaUtils.createDirectStream[String, String](
             ssc,
             PreferConsistent,
             Subscribe[String,String](topics, kafkaParams))
val sparkExecutorsCount = sc.getConf.getInt("spark.executor.instances", 1)
//Some code
stream.foreachRDD { rdd =>
    if(!rdd.isEmpty()) {
        val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
        val data = rdd.map(kafkaData => (getKey(kafkaData.value()), kafkaData.value()))
        val columns = Array("key", "value")
        data.toDF(columns: _*).coalesce(sparkExecutorsCount)
            .write.mode(SaveMode.Append)
            .partitionBy("key").text(MY_PATH)

       stream.asInstanceOf[CanCommitOffsets].commitAsync(offsetRanges)
    } else {
        //handle empty RDD
    }
}

请告知如何使我的Spark应用程序将其他文件写入输出目录。谢谢

1 个答案:

答案 0 :(得分:0)

coalesce 不会重新组合键上的数据,它可以连接分区,而无需在分区之间重新分配记录。在您的示例中, partitionBy 不是在Dataframe上调用,而是在 .write 函数返回的DataFrameWriter上调用。在这种情况下,列 key 看起来具有3个值,因此3个文件夹(key = 1,key = 2,key = 3)和每个文件夹中具有相同时间戳的3个文件可以通过数据框至少具有3个分区,因为每个分区运行时将有一个写入器,该写入器必须输出到3个文件夹中(key = 1,key = 2,key = 3)。我怀疑“ sparkExecutorsCount == 6”没有影响,可能是因为Kafka只为您提供了3个分区,在这种情况下,合并没有任何影响。

要仅将每个关键文件夹下移至1个文件,您可以尝试 coalesce(1)或代替使用 repartition($“ key”)并保留现有文件 paritionBy

data.toDF(columns: _*).repartition($"key")
        .write.mode(SaveMode.Append)
        .partitionBy("key").text(MY_PATH)

data.toDF(columns: _*).repartition(sparkExecutorsCount, $"key")
        .write.mode(SaveMode.Append)
        .partitionBy("key").text(MY_PATH)