在我的程序中,我有一个返回一些RDD的方法,让我们调用它myMethod
,它接受一个不可序列化的参数,让RDD属于Long
类型(我的真正的RDD是一个元组类型,但只包含基本类型。)
当我尝试这样的事情时:
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
(即某些常量)时,它会运行。
从序列化跟踪中,它尝试序列化NonSerializableThing
并在那里扼流圈,但我仔细检查了我的方法,这个对象永远不会出现在RDD中。
当我尝试直接收集myMethod
的输出时,即
myMethod(x, l).take(1) foreach println
我也没有遇到任何问题。
该方法使用NonSerializableThing
来获取一个(本地)Seq值,在这些值上进行多个Cassandra查询(这是必需的,因为我需要构造要查询的分区键),如下所示:
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))
}
getSomeSeq
和someOtherSeq
返回普通非火花Seq
我想要实现的是" union"多个Cassandra查询。
这可能是什么问题?
按照Jem Tucker的要求编辑,附录:我班上的内容是这样的:
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
我测试了这个" live"进入Spark shell以及通过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
作为隐式构造函数参数传入其中。我想如果我做这个瞬态,它会(无用地)被序列化但不会引起任何问题。
答案 0 :(得分:2)
当用author.username
替换l
时,Spark不再尝试使用方法/变量序列化类,因此不会抛出错误。
您应该能够通过将1L
标记为短暂来解决问题,例如
val x: NonSerializableThing = ...
这意味着当序列化类时,应忽略此变量。