Scala Spark:如何使用mapPartition并创建/关闭每个分区的连接

Scala Spark:如何使用mapPartition并创建/关闭每个分区的连接,scala,apache-spark,rdd,Scala,Apache Spark,Rdd,所以,我想对我的spark数据帧执行某些操作,将它们写入DB,并在最后创建另一个数据帧。看起来是这样的: import sqlContext.implicits._ val newDF = myDF.mapPartitions( iterator => { val conn = new DbConnection iterator.map( row => { addRowToBatch(row) convertRo

所以,我想对我的spark数据帧执行某些操作,将它们写入DB,并在最后创建另一个数据帧。看起来是这样的:

import sqlContext.implicits._

val newDF = myDF.mapPartitions(
  iterator => {
    val conn = new DbConnection
    iterator.map(
       row => {
         addRowToBatch(row)
         convertRowToObject(row)
     })
    conn.writeTheBatchToDB()
    conn.close()
  })
  .toDF()
这给了我一个错误,因为mapPartitions期望返回类型为
迭代器[NotInferedR]
,但这里是
单元
。我知道这在forEachPartition中是可能的,但我也想做映射。单独做这件事将是一项开销(额外的工作)。怎么办


谢谢

匿名函数实现中的最后一个表达式必须是返回值:

import sqlContext.implicits._

val newDF = myDF.mapPartitions(
  iterator => {
    val conn = new DbConnection
    // using toList to force eager computation - make it happen now when connection is open
    val result = iterator.map(/* the same... */).toList
    conn.writeTheBatchToDB()
    conn.close()
    result.iterator
  }
).toDF()

在大多数情况下,如果不降低作业的速度,使用迭代器将导致执行失败。因此,我所做的是检查迭代器是否已经为空,然后执行清理例程

rdd.mapPartitions(itr => {
    val conn = new DbConnection
    itr.map(data => {
       val yourActualResult = // do something with your data and conn here
       if(itr.isEmpty) conn.close // close the connection
       yourActualResult
    })
})

起初认为这是一个火花问题,但实际上是一个scala问题

如果我必须在
iterator.map()函数中使用
conn
怎么办?我不会得到一个连接已经关闭的异常吗?好吧-你是对的-因为iterator.map的惰性,实际计算只会在使用
结果
迭代器时发生,因此-在连接关闭之后。我将修正答案以反映这一点-谢谢谢谢!我把它作为一个单独的问题来问。你可以看一看,我会用同样的懒方法关闭它,而不使用toList:
(iterator.map(…)++Seq(null)).filter(!=null |{close;false})