执行程序上的Spark对象(单例)序列化

时间:2017-11-11 19:19:08

标签: scala apache-spark serialization singleton

我不确定我想要实现的目标是可能的。我所知道的是我从执行程序访问单个对象以确保它的构造函数在每个执行程序上只被调用一次。此模式已经过验证,可以在我的代码库中按类似用例的预期工作。

然而,我想知道的是,如果我在驱动程序上初始化对象后可以运送该对象。在这种情况下, 访问ExecutorAccessedObject.y时,理想情况下它不会调用println而只返回值。这是一个高度简化的版本,实际上,我想在驱动程序上调用一些外部系统,因此当在执行程序上访问时,它不会重新调用该外部系统。我很好@transient lazy val x在执行程序上重新初始化一次,因为它将保存一个无法序列化的连接池。

object ExecutorAccessedObject extends Serializable {
  @transient lazy val x: Int = {
    println("Ok with initialzing this on the executor. I.E. database connection pool")
    1
  }

  val y: Int = {
    // call some external system to return a value.
    // I do not want to call the external system from the executor
    println(
      """
        |Idealy, this would not be printed on the executor.
        |return value 1 without re initializing
      """)
    1
  }
  println("The constructor will be initialized Once on each executor")
}


someRdd.mapPartitions { part =>
  ExecutorAccessedObject
  ExecutorAccessedObject.x // first time accessed should re-evaluate
  ExecutorAccessedObject.y // idealy, never re-evaluate and return 1
  part
}

我试图用广播变量来解决这个问题,但我不确定如何在单例对象中访问广播变量。

1 个答案:

答案 0 :(得分:3)

  

我想知道的是,如果我在驱动程序上初始化对象后可以运送它。

你做不到。 Objects,作为单身人士,永远不会被运送到遗嘱执行人。无论何时第一次访问对象,都会在本地初始化。

如果调用的结果是可序列化的,只需将其单独传递,作为ExecutorAccessedObject的参数(隐式或显式)或使ExecutorAccessedObject可变(并添加所需的同步)。