Spark Streaming:foreachPartition

时间:2016-02-02 09:51:31

标签: scala apache-spark spark-streaming

我有一个火花流媒体工作,从Kafka读取并与Postgres中的现有表格进行一些比较,然后再次写入Postrges。这就是它的样子:

val message = KafkaUtils.createStream(...).map(_._2)

message.foreachRDD( rdd => {

  if (!rdd.isEmpty){
    val kafkaDF = sqlContext.read.json(rdd)
    println("First")

    kafkaDF.foreachPartition(
      i =>{
        val jdbcDF = sqlContext.read.format("jdbc").options(
          Map("url" -> "jdbc:postgresql://...",
            "dbtable" -> "table", "user" -> "user", "password" -> "pwd" )).load()

        createConnection()
        i.foreach(
          row =>{
            println("Second")
            connection.sendToTable()
          }
        )
        closeConnection()
      }
    )

此代码在val jbdcDF = ...

给我NullPointerException

我做错了什么?此外,我的日志"First"有效,但"Second"并未显示在日志中的任何位置。我用kafkaDF.collect().foreach(...)尝试了整个代码并且它运行良好,但性能非常差。我希望用foreachPartition替换它。

由于

2 个答案:

答案 0 :(得分:3)

目前尚不清楚createConnectioncloseConnectionconnection.sendToTable内是否存在任何问题,但基本问题是尝试嵌套操作/转换。它不支持Spark和Spark Streaming没有什么不同。

这意味着嵌套的DataFrame初始化(val jdbcDF = sqlContext.read.format ...)根本无法工作,应该被删除。如果您将其用作参考,则应在与kafkaDF相同的级别创建,并使用标准转换(unionAlljoin,...)进行参考。

如果由于某种原因它不是一个可接受的解决方案,你可以在forEachPartition内创建普通的JDBC连接并在PostgreSQL表上运行(我想这是你在sendToTable内已经做过的事情)。 / p>

答案 1 :(得分:1)

正如@ zero323正确指出的那样,你不能广播你的jdbc连接,也不能创建嵌套的RDD。 Spark根本不支持在现有闭包中使用sparkContext或sqlContext,即foreachPartition,因此空指针异常。

有效解决这个问题的唯一方法是在foreachPartition中创建JDBC连接并直接在其上执行SQL以执行任何操作,然后使用相同的连接写回记录。

关于你的第二个编辑问题:

变化:

kafkaDF.foreachPartition(..)

kafkaDF.repartition(numPartition).foreachPartition(..)

其中numPartition是所需的分区数。这将增加分区数量。如果您有多个执行程序(每个执行程序有多个任务),它们将并行运行。