如何在没有覆盖的情况下将Spark Streaming输出写入HDFS

时间:2017-06-12 06:19:40

标签: apache-kafka spark-streaming

经过一些处理我有一个DStream [String,ArrayList [String]],所以当我使用saveAsTextFile将它写入hdfs时,每次批处理后都会覆盖数据,所以如何通过追加到前面的结果来写新的结果< / p>

output.foreachRDD(r => {
  r.saveAsTextFile(path)
})

编辑:: 如果有人可以帮助我将输出转换为avro格式,然后附加

写入HDFS

4 个答案:

答案 0 :(得分:3)

saveAsTextFile不支持追加。如果使用固定文件名调用,则每次都会覆盖它。 我们每次都可以saveAsTextFile(path+timestamp)保存到新文件。这是DStream.saveAsTextFiles(path)

的基本功能

支持append的易于访问的格式是Parquet。我们首先将数据RDD转换为DataFrameDataset,然后我们可以从该抽象之上提供的写入支持中受益。

case class DataStructure(field1,..., fieldn)

... streaming setup, dstream declaration, ...

val structuredOutput = outputDStream.map(record => mapFunctionRecordToDataStructure)
structuredOutput.foreachRDD(rdd => 
  import sparkSession.implicits._
  val df = rdd.toDF()
  df.write.format("parquet").mode("append").save(s"$workDir/$targetFile")

})

请注意,随着时间的推移附加到Parquet文件会变得更加昂贵,因此仍然需要不时地旋转目标文件。

答案 1 :(得分:0)

如果要在文件系统上追加相同的文件并存储,请将其存储为镶木地板文件。你可以通过

来做到这一点
  kafkaData.foreachRDD( rdd => {
  if(rdd.count()>0)
  {
    val df=rdd.toDF()
    df.write(SaveMode.Append).save("/path")
   }

答案 2 :(得分:0)

将流输出存储到HDFS始终会创建一个新文件,即使您在使用parquet的情况下使用append导致在Namenode上出现小文件问题的情况下也是如此。我可能建议将您的输出写入序列文件,在其中您可以继续追加到同一文件。

答案 3 :(得分:0)

我在这里解决了没有数据框的问题

import java.time.format.DateTimeFormatter
import java.time.LocalDateTime

 messages.foreachRDD{ rdd =>
    rdd.repartition(1)
    val eachRdd = rdd.map(record => record.value)
    if(!eachRdd.isEmpty) {
      eachRdd.saveAsTextFile(hdfs_storage + DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(LocalDateTime.now) + "/")
    }
  }