为什么在过滤器中使用set会导致“org.apache.spark.SparkException:Task not serializable”?

时间:2015-11-29 14:09:00

标签: scala apache-spark rdd

我正在尝试根据列表中这些对象的字段过滤RDD中的对象集合。

我尝试的方法与此处相同: Filter based on another RDD in Spark

val namesToFilterOn = sc.textFile("/names_to_filter_on.txt").collect.toSet

val usersRDD = userContext.loadUsers("/user.parquet")

这有效:

usersRDD.filter(user =>  Set("Pete","John" ).contains( user.firstName )).first

当我尝试

usersRDD.filter(user => namesToFilterOn.contains( user.firstName )).first

我收到此错误

org.apache.spark.SparkException: Task not serializable
Caused by: java.io.NotSerializableException: org.apache.spark.SparkContext

我尝试这个时遇到同样的错误

val shortTestList = Set("Pete","John" )

usersRDD.filter(user => shortTestList .contains( user.firstName )).first

为什么在这些过滤器语句中指定一组名称/字符串时会出现这个错误?

据我所知,这应该可行,我没有在filter语句中的任何地方指定SparkContext。那么为什么会出错呢?怎么不得到错误?

我使用的Spark版本是1.5.2。

我还尝试先播放一组名字。

val namesToFilterOnBC = sc.broadcast(namesToFilterOn)
usersRDD.filter(user => namesToFilterOnBC.value.contains( user.firstName )).first

这又导致同样的错误

org.apache.spark.SparkException: Task not serializable
Caused by: java.io.NotSerializableException: org.apache.spark.SparkContext

2 个答案:

答案 0 :(得分:1)

原因是val namesToFilterOn = sc.textFile("/names_to_filter_on.txt").collect.toSet属于包含不可序列化的val并因此包含错误的对象。

user => namesToFilterOn.contains( user.firstName )转换为字节格式以通过线路发送给执行程序时,Spark会检查是否存在对不可序列化对象的引用,并且SparkContext就在其中。

Spark似乎找到了一个引用非序列化SparkContext的地方并抛出了异常。

解决方案是将val namesToFilterOn = sc.textFile("/names_to_filter_on.txt").collect.toSetval shortTestList = Set("Pete","John" )包装为Scala中object的单独方法。您还可以在闭包内使用其他val shortTestList(如Job aborted due to stage failure: Task not serializable中所述)或broadcast

您可能会发现文档SIP-21 - Spores非常适合该案例。

答案 1 :(得分:0)

询问userContext的开发人员并通过不显式实例化userContext而只是导入其函数来解决问题。

import userContext._
sc.loadUsers("/user.parquet")
usersRDD.filter(user => namesToFilterOn.contains( user.firstName )).first

而不是

val userContext = new UserContext(sc)
userContext.loadUsers("/user.parquet")
usersRDD.filter(user => namesToFilterOn.contains( user.firstName )).first