Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark Spark Streaming textFileStream不支持通配符_Apache Spark_Hdfs_Spark Streaming - Fatal编程技术网

Apache spark Spark Streaming textFileStream不支持通配符

Apache spark Spark Streaming textFileStream不支持通配符,apache-spark,hdfs,spark-streaming,Apache Spark,Hdfs,Spark Streaming,我设置了一个简单的测试来从S3流式传输文本文件,当我尝试类似的东西时,它就开始工作了 val input = ssc.textFileStream("s3n://mybucket/2015/04/03/") s3n://mybucket/<YEAR>/<MONTH>/<DAY>/<LogfileName> 在桶里,我会把日志文件放进去,一切都会好的 但是,如果它们是子文件夹,它将找不到放入子文件夹的任何文件(是的,我知道hdfs实际上不使用文件

我设置了一个简单的测试来从S3流式传输文本文件,当我尝试类似的东西时,它就开始工作了

val input = ssc.textFileStream("s3n://mybucket/2015/04/03/")
s3n://mybucket/<YEAR>/<MONTH>/<DAY>/<LogfileName>
在桶里,我会把日志文件放进去,一切都会好的

但是,如果它们是子文件夹,它将找不到放入子文件夹的任何文件(是的,我知道hdfs实际上不使用文件夹结构)

因此,我尝试简单地使用通配符,就像我以前使用标准spark应用程序所做的那样

val input = ssc.textFileStream("s3n://mybucket/2015/04/*")
但当我尝试这个时,它抛出了一个错误

java.io.FileNotFoundException: File s3n://mybucket/2015/04/* does not exist.
at org.apache.hadoop.fs.s3native.NativeS3FileSystem.listStatus(NativeS3FileSystem.java:506)
at org.apache.hadoop.fs.FileSystem.listStatus(FileSystem.java:1483)
at org.apache.hadoop.fs.FileSystem.listStatus(FileSystem.java:1523)
at org.apache.spark.streaming.dstream.FileInputDStream.findNewFiles(FileInputDStream.scala:176)
at org.apache.spark.streaming.dstream.FileInputDStream.compute(FileInputDStream.scala:134)
at org.apache.spark.streaming.dstream.DStream$$anonfun$getOrCompute$1$$anonfun$1.apply(DStream.scala:300)
at org.apache.spark.streaming.dstream.DStream$$anonfun$getOrCompute$1$$anonfun$1.apply(DStream.scala:300)
at scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)
at org.apache.spark.streaming.dstream.DStream$$anonfun$getOrCompute$1.apply(DStream.scala:299)
at org.apache.spark.streaming.dstream.DStream$$anonfun$getOrCompute$1.apply(DStream.scala:287)
at scala.Option.orElse(Option.scala:257)
.....
我知道,在为标准spark应用程序读取fileInput时,可以使用通配符,但在执行流式输入时,它不会这样做,也不会自动处理子文件夹中的文件。这里有我遗漏的东西吗

最终,我需要的是一个24/7运行的流式作业,它将监控一个S3存储桶,其中按日期放置了日志

大概是

val input = ssc.textFileStream("s3n://mybucket/2015/04/03/")
s3n://mybucket/<YEAR>/<MONTH>/<DAY>/<LogfileName>
s3n://mybucket////
有没有办法把它放在最上面的文件夹中,它会自动读取显示在任何文件夹中的文件(因为日期显然每天都在增加)

编辑

因此,在深入研究文档时,它指出嵌套目录不受支持

有人能解释一下为什么会这样吗


另外,由于我的文件将根据日期嵌套,在我的流应用程序中解决这个问题的好方法是什么?这有点复杂,因为日志需要几分钟才能写入S3,因此当天最后写入的文件可能会写入前一天的文件夹,即使我们进入新的一天只有几分钟。

我们也遇到了同样的问题。我们用逗号连接子文件夹名称

List<String> paths = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

try {        
    Date start = sdf.parse("2015/02/01");
    Date end = sdf.parse("2015/04/01");

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(start);        

    while (calendar.getTime().before(end)) {
        paths.add("s3n://mybucket/" + sdf.format(calendar.getTime()));
        calendar.add(Calendar.DATE, 1);
    }                
} catch (ParseException e) {
    e.printStackTrace();
}

String joinedPaths = StringUtils.join(",", paths.toArray(new String[paths.size()]));
val input = ssc.textFileStream(joinedPaths);
List path=new ArrayList();
SimpleDataFormat sdf=新的SimpleDataFormat(“yyyy/MM/dd”);
试试{
开始日期=sdf.parse(“2015/02/01”);
日期结束=sdf.parse(“2015/04/01”);
日历=Calendar.getInstance();
日历。设置时间(开始);
while(calendar.getTime().before(end)){
add(“s3n://mybucket/”+sdf.format(calendar.getTime());
calendar.add(calendar.DATE,1);
}                
}捕获(解析异常){
e、 printStackTrace();
}
String joinedPaths=StringUtils.join(“,”,paths.toArray(新字符串[path.size()]);
val输入=ssc.textFileStream(joinedpath);
我希望通过这种方式解决您的问题。

通过扩展FileInputDStream,可以创建一些“丑陋但有效的解决方案”。 编写
sc.textFileStream(d)
相当于

new FileInputDStream[LongWritable, Text, TextInputFormat](streamingContext, d).map(_._2.toString)
您可以创建将扩展FileInputDStream的CustomFileInputDStream。自定义类将从FileInputDStream类复制compute方法,并根据需要调整findNewFiles方法

将findNewFiles方法更改为:

 private def findNewFiles(currentTime: Long): Array[String] = {
    try {
      lastNewFileFindingTime = clock.getTimeMillis()

  // Calculate ignore threshold
  val modTimeIgnoreThreshold = math.max(
    initialModTimeIgnoreThreshold,   // initial threshold based on newFilesOnly setting
    currentTime - durationToRemember.milliseconds  // trailing end of the remember window
  )
  logDebug(s"Getting new files for time $currentTime, " +
    s"ignoring files older than $modTimeIgnoreThreshold")
  val filter = new PathFilter {
    def accept(path: Path): Boolean = isNewFile(path, currentTime, modTimeIgnoreThreshold)
  }
  val newFiles = fs.listStatus(directoryPath, filter).map(_.getPath.toString)
  val timeTaken = clock.getTimeMillis() - lastNewFileFindingTime
  logInfo("Finding new files took " + timeTaken + " ms")
  logDebug("# cached file times = " + fileToModTime.size)
  if (timeTaken > slideDuration.milliseconds) {
    logWarning(
      "Time taken to find new files exceeds the batch size. " +
        "Consider increasing the batch size or reducing the number of " +
        "files in the monitored directory."
    )
  }
  newFiles
} catch {
  case e: Exception =>
    logWarning("Error finding new files", e)
    reset()
    Array.empty
}
}

致:

将检查所有一级子文件夹中的文件,您可以将其调整为使用批处理时间戳,以便访问相关的“子目录”

我如前所述创建了CustomFileInputDStream,并通过调用以下命令将其激活:

new CustomFileInputDStream[LongWritable, Text, TextInputFormat](streamingContext, d).map(_._2.toString)
这似乎符合我们的期望

当我写这样的解决方案时,我必须添加一些要点以供考虑:

  • 您正在打破Spark封装,并创建一个定制类,随着时间的推移,您将不得不单独支持该类

  • 我相信这样的解决方案是最后的选择。如果您的用例可以通过不同的方式实现,通常最好避免这样的解决方案

  • 如果您在S3上有很多“子目录”,并且要检查每个子目录,那么您将为此付出代价

  • 了解Databricks是否仅仅因为可能的性能损失而不支持嵌套文件是非常有趣的,也许还有更深层次的原因我没有考虑过


实际上,我不确定s3是否支持通配符……它肯定支持。在过去的8个月里,我的工作一直在使用通配符。另外,为了检查是否正常,我刚刚用通配符输入运行了一个作业,工作正常。我确实注意到,要求您不要执行类似于s3n://mybucket/2015/04*的操作有点挑剔,正如线程“main”中所说的那样java.io.IOException:不是一个文件:s3n://mybucket/2015/04/01这很有意义,因为它不是一个文件,但如果您执行s3n://mybucket/2015/04/*操作,它将正确解析days子文件夹中的所有文件。。。。我觉得这是个问题,我要投票赞成这个问题。我记得有过类似的问题,但我不记得我是如何解决的。我很感激。这听起来确实像是一个常见的实现。你如何处理更大的结束日期?通过编译和重新启动程序?或者我遗漏了什么?我有一个类似的用例,如果我没有找到替代方案,我会考虑走这条路。我使用YYYY-MM-DD-HH格式对子文件夹进行了日期分区。每小时都会创建一个新文件夹,并将文件上载到其中。因此,我不必扫描所有子文件夹(仅最后三个子文件夹),也不会遇到性能问题。我更担心此类代码的可维护性和重启状态管理(上次扫描了哪个小时的文件夹+文件,等等)。看看你是否可以分享你对这段代码的想法,甚至是对你的自定义FileDstream的代码。如果你在流中使用检查点目录,那么当你重新启动应用程序时,你将首先重新安排在应用程序停机期间应该执行的所有批处理。e、 g如果您的流媒体时间间隔为1分钟,并且您的应用程序在10:00关闭并在10:30备份,当它将启动时,应用程序将尝试执行10:01、10:02等批处理。现在,如果您以从currentTime派生您扫描的文件夹的方式实现findNewFiles(currentTime),您将能够扫描“正确的”重新启动后的文件。请注意,currentTime不是