我们正在运行一个Spark流式传输作业,它从目录中检索文件(使用textFileStream)。 我们遇到的一个问题是作业已关闭,但文件仍在添加到目录中。 一旦作业再次启动,那些文件就不会被拾取(因为它们不是新的或在作业运行时被更改)但我们希望它们被处理。
1)有解决方案吗?有没有办法跟踪哪些文件已被处理,我们可以强迫"强迫"要收拾旧文件?
2)有没有办法删除处理过的文件?
答案 0 :(得分:1)
以下文章几乎涵盖了您的所有问题。
https://blog.yanchen.im/2016/06/28/fileinputdstream-in-spark-streaming/
1)有解决方案吗?有没有办法跟踪哪些文件已被处理,我们可以强迫"强迫"要拿起旧文件?
当启动作业/应用程序时,流阅读器使用系统时钟启动批处理窗口。显然,之前创建的所有文件都将被忽略。尝试启用点校验。
2)有没有办法删除已处理的文件?
删除文件可能是不必要的。如果检查点有效,则Spark会识别未处理的文件。如果由于某种原因要删除文件,请实现自定义输入格式和阅读器(请参阅文章)以捕获文件名并根据需要使用此信息。但我不推荐这种方法。
答案 1 :(得分:0)
是否可以删除已处理的文件?
根据我的经验,我无法使用检查点功能,因此我不得不删除/移动进入每个批次的已处理文件。
获取这些文件的方法有些棘手,但是基本上可以说它们是当前RDD
的祖先(依赖项)。然后,我使用的是一种递归方法,该方法会爬网该结构并恢复以RDD
开头的hdfs
的名称。
/**
* Recursive method to extract original metadata files involved in this batch.
* @param rdd Each RDD created for each batch.
* @return All HDFS files originally read.
*/
def extractSourceHDFSFiles(rdd: RDD[_]): Set[String] = {
def extractSourceHDFSFilesWithAcc(rdd: List[RDD[_]]) : Set[String] = {
rdd match {
case Nil => Set()
case head :: tail => {
val name = head.toString()
if (name.startsWith("hdfs")){
Set(name.split(" ")(0)) ++ extractSourceHDFSFilesWithAcc(head.dependencies.map(_.rdd).toList) ++ extractSourceHDFSFilesWithAcc(tail)
}
else {
extractSourceHDFSFilesWithAcc(head.dependencies.map(_.rdd).toList) ++ extractSourceHDFSFilesWithAcc(tail)
}
}
}
}
extractSourceHDFSFilesWithAcc(rdd.dependencies.map(_.rdd).toList)
}
因此,在forEachRDD
方法中,您可以轻松地调用它:
stream.forEachRDD(rdd -> {
val filesInBatch = extractSourceHDFSFiles(rdd)
logger.info("Files to be processed:")
// Process them
// Delete them when you are done
})