如何将Spark Streaming应用程序的输出写入单个文件

时间:2019-08-19 06:49:28

标签: apache-spark apache-spark-sql streaming spark-streaming csv-write-stream

我正在使用Spark Streaming从Kafka读取数据,并传递给py文件进行预测。它返回预测以及原始数据。它会将原始数据及其预测信息保存到文件中,但是会为每个RDD创建一个文件。 我需要一个包含所有收集到的数据的文件,直到停止程序保存到一个文件为止。

我尝试过writeStream,它甚至不创建单个文件。 我尝试使用append将其保存到拼花地板,但它会为每个RDD创建多个文件,该文件为1。 我试图用追加模式编写仍然有多个文件作为输出。 下面的代码创建一个文件夹output.csv并将所有文件输入其中。

 def main(args: Array[String]): Unit = {
    val ss = SparkSession.builder()
      .appName("consumer")
      .master("local[*]")
      .getOrCreate()

    val scc = new StreamingContext(ss.sparkContext, Seconds(2))


    val kafkaParams = Map[String, Object](
        "bootstrap.servers" -> "localhost:9092",
        "key.deserializer"-> 
"org.apache.kafka.common.serialization.StringDeserializer",
        "value.deserializer"> 
"org.apache.kafka.common.serialization.StringDeserializer",
        "group.id"-> "group5" // clients can take
      )
mappedData.foreachRDD(
      x =>
    x.map(y =>       
ss.sparkContext.makeRDD(List(y)).pipe(pyPath).toDF().repartition(1)
.write.format("csv").mode("append").option("truncate","false")
.save("output.csv")
          )
    )
scc.start()
scc.awaitTermination()

在流式传输期间,我只需要一个文件,所有语句一一收集。

任何帮助将不胜感激,谢谢您的期待。

2 个答案:

答案 0 :(得分:2)

一旦写入,您将无法修改hdfs中的任何文件。如果您希望实时写入文件(每2秒将来自流作业的数据块追加到同一文件中),则由于hdfs文件是不可变的,因此根本不允许这样做。我建议您尝试编写一个从多个文件读取的读取逻辑(如果可能)。

但是,如果必须从一个文件中读取文件,则建议在将输出写入单个csv / parquet文件夹后使用“ Append” SaveMode(这将为每个块创建零件文件)中的两种方法之一您每2秒写一次)。

  1. 您可以在此文件夹的顶部创建一个配置单元表,以从该表中读取数据。
  2. 您可以在spark中编写一个简单的逻辑来读取包含多个文件的该文件夹,然后使用reparation(1)或coalesce(1)将其作为单个文件写入另一个hdfs位置,然后从该位置读取数据。见下文:

    spark.read.csv("oldLocation").coalesce(1).write.csv("newLocation")
    

答案 1 :(得分:1)

repartition-建议在不增加任何分区的情况下使用repartition,因为它涉及对所有数据的改组。

coalesce-建议在减少分区数量的同时使用合并。例如,如果您有3个分区,并且想要将其减少到2个分区,则Coalesce会将第3个分区数据移至分区1和2。分区1和2将保留在同一Container中。但是重新分区将在所有分区中重新排列数据,因此网络使用率执行器之间的间隔会很高,并且会影响性​​能。

明智的结合性能优于分区,同时减少了分区数量。

因此,在编写use选项时会结合在一起。 例如:df.write.coalesce