繁体   English   中英

奇怪的“任务无法序列化”

[英]Strange “Task not serializable” with Spark

在我的程序中,我有一个返回一些RDD的方法,我们称其为myMethod ,它带有一个不可序列化的参数,并且使RDD的类型为Long (我的真实RDD是一个Tuple类型,但只包含基本类型)。

当我尝试这样的事情:

val x: NonSerializableThing = ...
val l: Long = ...
myMethod(x, l).map(res => res + l) // myMethod's RDD does NOT include the NonSerializableThing

我得到Task not serializable

当我用res + l res + 1L (即某个常数)替换res + l ,它将运行。

从序列化跟踪中,它尝试序列化NonSerializableThing并在此阻塞,但是我仔细检查了我的方法,此对象从未出现在RDD中。

当我尝试直接收集myMethod输出时,即

myMethod(x, l).take(1) foreach println

我也没问题。

该方法使用NonSerializableThing获取在其上进行多个Cassandra查询的值的(本地)Seq(这是必需的,因为我需要构造要查询的分区键),如下所示:

def myMethod(x: NonSerializableThing, l: Long): RDD[Long] = {
  val someParam1: String = x.someProperty
  x.getSomeSeq.flatMap(y: OtherNonSerializableThing => {
    val someParam2: String = y.someOtherProperty
    y.someOtherSeq.map(someParam3: String =>
      sc.cassandraTable("fooKeyspace", "fooTable").
      select("foo").
      where("bar=? and quux=? and baz=? and l=?", someParam1, someParam2, someParam3, l).
      map(_.getLong(0))
  }.reduce((a, b) => a.union(b))
}

getSomeSeqsomeOtherSeq返回普通的非火花Seq

我要实现的是“联合”多个Cassandra查询。

这可能是什么问题?

编辑,附录,按杰姆·塔克的要求:

我在课堂上所学的是这样的:

implicit class MySparkExtension(sc: SparkContext) {

  def getThing(/* some parameters */): NonSerializableThing = { ... }

  def myMethod(x: NonSerializableThing, l: Long): RDD[Long] = {
    val someParam1: String = x.someProperty
    x.getSomeSeq.flatMap(y: OtherNonSerializableThing => {
      val someParam2: String = y.someOtherProperty
      y.someOtherSeq.map(someParam3: String =>
        sc.cassandraTable("fooKeyspace", "fooTable").
        select("foo").
        where("bar=? and quux=? and baz=? and l=?", someParam1, someParam2, someParam3, l).
        map(_.getLong(0))
    }.reduce((a, b) => a.union(b))
  }
}

这在包对象中声明。 问题发生在这里:

// SparkContext is already declared as sc
import my.pkg.with.extension._

val thing = sc.getThing(/* parameters */)
val l = 42L
val rdd = sc.myMethod(thing, l)
// until now, everything is OK.
// The following still works:
rdd.take(5) foreach println
// The following causes the exception:
rdd.map(x => x >= l).take(5) foreach println
// While the following works:
rdd.map(x => x >= 42L).take(5) foreach println

我测试了这个输入的“实时”到Spark外壳以及通过spark-submit的算法中。

我现在要尝试的内容(根据我的最新评论)如下:

implicit class MySparkExtension(sc: SparkContext) {

  def getThing(/* some parameters */): NonSerializableThing = { ... }

  def myMethod(x: NonSerializableThing, l: Long): RDD[Long] = {
    val param1 = x.someProperty
    val partitionKeys =
      x.getSomeSeq.flatMap(y => {
        val param2 = y.someOtherProperty
        y.someOtherSeq.map(param3 => (param1, param2, param3, l)
      }
    queryTheDatabase(partitionKeys)
  }

  private def queryTheDatabase(partitionKeys: Seq[(String, String, String, Long)]): RDD[Long] = {
    partitionKeys.map(k =>
      sc.cassandraTable("fooKeyspace", "fooTable").
         select("foo").
         where("bar=? and quux=? and baz=? and l=?", k._1, k._2, k._3, k._4).
         map(_.getLong(0))
    ).reduce((a, b) => a.union(b))
  }
}

我相信这可以解决问题,因为RDD是在方法queryTheDatabase构造的,现在不存在NonSerializableThing

另一个选择可能是: NonSerializableThing确实可以序列化,但是我在其中传递SparkContext作为隐式构造函数参数。 我认为,如果我使此瞬变,它将(无用)被序列化,但不会引起任何问题。

当您用1L替换l ,Spark不再尝试使用中的方法/变量来序列化该类,因此不会引发错误。

您应该能够通过将val x: NonSerializableThing = ...标记为瞬态来进行修复,例如

@transient
val x: NonSerializableThing = ...

这意味着当类被序列化时,该变量应被忽略。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM