使用saveAsNewAPIHadoopFile时会覆盖文件

时间:2016-03-22 16:01:44

标签: apache-spark spark-streaming

我们正在使用Spark 1.4进行Spark Streaming。 Kafka是Spark Stream的数据源。

记录每秒都在Kafka上发布。我们的要求是将Kafka上发布的记录每分钟存储在一个文件夹中。流将每五秒读取一次记录。例如,在1200 PM和1201PM期间发布的记录存储在文件夹“1200”中;在1201PM到1202PM之间的文件夹“1201”等等。

我写的代码如下

//First Group records in RDD by date
stream.foreachRDD (rddWithinStream -> {
    JavaPairRDD<String, Iterable<String>> rddGroupedByDirectory = rddWithinStream.mapToPair(t -> {
    return new Tuple2<String, String> (targetHadoopFolder, t._2());
}).groupByKey();
// All records grouped by folders they will be stored in


// Create RDD for each target folder.
for (String hadoopFolder : rddGroupedByDirectory.keys().collect()) {
    JavaPairRDD <String, Iterable<String>> rddByKey = rddGroupedByDirectory.filter(groupedTuples -> {
    return groupedTuples._1().equals(hadoopFolder);
    });

// And store it in Hadoop 
    rddByKey.saveAsNewAPIHadoopFile(directory, String.class, String.class, TextOutputFormat.class);
}

由于Stream每五秒处理一次数据,因此saveAsNewAPIHadoopFile会在一分钟内多次调用。这会导致每次都覆盖“Part-00000”文件。

我原以为在“directory”参数指定的目录中,即使我有一个sinlge工作节点,saveAsNewAPIHadoopFile也会继续创建part-0000N文件。

非常感谢任何帮助/替代方案。

感谢。

2 个答案:

答案 0 :(得分:1)

在这种情况下,您必须自己构建输出路径和文件名。只有在DStream上直接调用输出操作时,增量文件命名才有效(不是每RDD}。

stream.foreachRDD中的参数函数可以获得每个微批次的Time信息。参考Spark documentation

def foreachRDD(foreachFunc: (RDD[T], Time) ⇒ Unit)

因此,您可以按如下方式保存每个RDD

stream.foreachRDD((rdd, time) -> {
    val directory = timeToDirName(prefix, time)
    rdd.saveAsNewAPIHadoopFile(directory, String.class, String.class, TextOutputFormat.class);
})

答案 1 :(得分:0)

您可以尝试--

将过程分为2个步骤:

Step-1 :- Write Avro file using saveAsNewAPIHadoopFile to <temp-path>
Step-2 :- Move file from <temp-path> to <actual-target-path>

希望这会有所帮助。