经过一些处理我有一个DStream [String,ArrayList [String]],所以当我使用saveAsTextFile将它写入hdfs时,每次批处理后都会覆盖数据,所以如何通过追加到前面的结果来写新的结果< / p>
output.foreachRDD(r => {
r.saveAsTextFile(path)
})
编辑:: 如果有人可以帮助我将输出转换为avro格式,然后附加
写入HDFS答案 0 :(得分:3)
saveAsTextFile
不支持追加。如果使用固定文件名调用,则每次都会覆盖它。
我们每次都可以saveAsTextFile(path+timestamp)
保存到新文件。这是DStream.saveAsTextFiles(path)
支持append
的易于访问的格式是Parquet。我们首先将数据RDD转换为DataFrame
或Dataset
,然后我们可以从该抽象之上提供的写入支持中受益。
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) + "/")
}
}