【问题标题】:Variable inside dataframe foreach gives null pointer exception in Scala数据帧 foreach 中的变量在 Scala 中给出空指针异常
【发布时间】:2022-07-21 16:18:29
【问题描述】:

我在尝试在“dataframe.foreach”函数中执行类函数时遇到了一些问题。我的自定义类将数据保存到 DynamoDB 表中。

发生的情况是,如果我有以下代码,它将无法工作,并会引发“空指针异常”,该异常指向执行“writer.writeRow(r)”的代码行:

object writeToDynamoDB extends App {

    val df: DataFrame = ...
    val writer: DynamoDBWriter = new DDBWriter(...)
  
    df
      .foreach(
        r => writer.writeRow(r)
      )
}

如果我使用相同的代码,但将代码放在代码块或 if 子句中,它将起作用:

object writeToDynamoDB extends App {

    val df: DataFrame = ...
    
    if(true) {
        val writer: DynamoDBWriter = new DDBWriter(...)
  
        df
          .foreach(
            r => writer.writeRow(r)
          )
    }
}

我想这与变量范围有关。即使在 IntelliJ 中,变量的颜色在第一种情况下也是紫色 + 斜体,在第二种情况下是“常规”灰色。我读过它,我们在 Scala 中有方法、字段和本地范围,但我无法将其与我正在尝试做的事情联系起来。

介绍后的一些问题:

  1. 谁能解释一下为什么 Scala 和/或 Spark 会有这种行为?

  2. 这里的解决办法是在函数里面放一些代码,代码块 或据我所知的“假” if 子句。关于 Spark 属性(随机播放等)是否存在任何可能的问题?

  3. 有没有其他方法可以进行这种类型的操作?

希望我是清楚的。

提前致谢。

问候

【问题讨论】:

  • 我敢打赌,问题是因为使用了App 而不是使用常规的main 方法。

标签: scala apache-spark apache-spark-sql


【解决方案1】:

如上所述,您的问题是由使用 App 特征时的延迟初始化引起的。 Spark docs 强烈反对:

请注意,应用程序应该定义一个 main() 方法,而不是扩展 scala.App。 scala.App 的子类可能无法正常工作。

原因可以在 App trait 本身的 Javadocs 中找到:

需要注意的是,这个 trait 是使用 DelayedInit 功能实现的,这意味着对象的字段在 main 方法执行之前不会被初始化。

这基本上意味着writer 在创建传递给foreach 的闭包时仍未初始化(因此null)。

正确且推荐的解决方案是为您的 Spark 应用程序使用标准的 main 方法:

object writeToDynamoDB  {
  def main(args: Array[String]): Unit = {
    val df: DataFrame = ...
    val writer: DynamoDBWriter = new DDBWriter(...)
    df.foreach(r => writer.writeRow(r))
  }
}

【讨论】:

    猜你喜欢
    • 2020-07-19
    • 2017-12-12
    • 1970-01-01
    • 2014-09-06
    • 2014-07-19
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多