如何使用JavaSparkContext处理Kafka记录中的文件名文件?

时间:2017-05-18 09:47:32

标签: java apache-spark apache-kafka spark-streaming

在我的应用程序中,Web UI应用程序在完成文件上载过程后将文件路径发送到Kafka。

我有一个Spark Streaming应用程序,它使用JavaSparkContextJavaPairInputDStream从Kafka中提取消息(因此它接收文件路径,但也可能有多个文件路径)。

我必须并行处理文件,并且需要将结果发送到另一个kafka流:

SparkConf conf = new SparkConf().setAppName("Task1").setMaster("local[*]");
    sc = new JavaSparkContext(conf);
    JavaStreamingContext ssc = new JavaStreamingContext(sc, new Duration(2000));

    Map<String, String> kafkaParams = new HashMap<>();
    kafkaParams.put("metadata.broker.list", "localhost:9092");
    Set<String> topics = Collections.singleton("topic1");

    JavaPairInputDStream<String, String> directKafkaStream = KafkaUtils.createDirectStream(ssc, String.class,
            String.class, StringDecoder.class, StringDecoder.class, kafkaParams, topics);

    directKafkaStream.foreachRDD(rdd -> {

        rdd.collect().forEach((t) -> {
            sendMessage(sc, t._2());
        });
    });

    ssc.start();
    ssc.awaitTermination();

sendMessage会将数据发送到文件中。

在上面的实现中,我在foreachRDD方法中使用JavaSparkContext,这不是最佳实践。我想并行处理文件。

2 个答案:

答案 0 :(得分:2)

我创建了一个函数sendMessage,它将是一个纯粹的Kafka生成器(不依赖于Spark,尤其是JavaSparkContext),它将向Kafka主题发送消息或者使用迭代器所有要发送的消息。

请参阅JMeter property

使用纯粹的Kafka生成器作为sendMessage我在Spark Streaming的转换中执行以下操作(内联注释应该给出一些关于每行发生的事情的提示):

def sendMessage(message: String) = {
  println(s"Sending $message to Kafka")
}
dstream.map(_.value).foreachRDD { rdd =>
  println(s"Received rdd: $rdd with ${rdd.count()} records")
  // take paths from RDD that contains Kafka records with the file names
  val files = rdd.collect()
  files.foreach { f =>
    // read a file `f` using Spark Core's RDD API
    rdd.sparkContext.textFile(f).map { line =>
      // do something with line
      // this is the place for a pure Spark transformation
      // it's as if you were outside Spark Streaming
      println(line)
      line
    }.foreachPartition { linesAfterProcessingPerPartition =>
      // send lines to Kafka
      // they have been processed using Spark
      linesAfterProcessingPerPartition.foreach { line =>
        sendMessage(message = line)
      }
    }
  }
}

我确信代码可以更清晰,但那就是Scala,你使用Java所以我会停在这里。

我强烈建议使用official documentation of Apache Kafka,因为很快就会取代Spark Streaming并成为Spark中的流媒体API。

答案 1 :(得分:1)

例如:

directKafkaStream.foreachRDD(new VoidFunction<JavaRDD<String>>() {
    public void call(JavaRDD<String> stringJavaRDD) throws Exception {
        stringJavaRDD.foreachPartition(new VoidFunction<Iterator<String>>() {
            public void call(Iterator<String> stringIterator) throws Exception {
                sendMessage(stringIterator);
            }
        });
    }