UDF返回“sc not serializable”

时间:2017-03-13 22:45:07

标签: scala apache-spark serialization

我有一个来自Cassandra数据库的数据集,使用下面的代码片段创建,然后我尝试在其中一个列上创建UDF。但是,这样做时我收到错误java.io.NotSerializableException: org.apache.spark.SparkConf

sc.stop()
val conf = new SparkConf(true).set("spark.cassandra.connection.host", "database.url").
  set("spark.cassandra.auth.username", "UNAME").
  set("spark.cassandra.auth.password", "PASSWORD");
val sc = new SparkContext("local", "test", conf);
val sqlContext = new SQLContext(sc);
import sqlContext.implicits._
val dfSurvey = sqlContext.read.format("org.apache.spark.sql.cassandra").
    options(Map("keyspace" -> "KEYSPACE_NAME", "table" -> "TABLE_NAME")).
    load()

我已将UDF简化为给定列中字符串的长度。出于测试目的,这里有2个UDF:

def test(s:String) : Int = s.length
val udf1 = udf((s:String) => test(s))
val udf2 = udf((s:String) => s.length)
val df1 = dfSurvey.withColumn("respText",responseFromJsonTest($"json"))
val df2 = dfSurvey.withColumn("respText",responseFromJsonTest2($"json"))

调用df2.show(1)工作正常,但调用df1.show(1)会出错。我不知道1路径如何需要sc的序列化而另一路径不需要。有人可以开导我吗?

1 个答案:

答案 0 :(得分:1)

test是包含类的方法(在帖子中没有显示,但毫无疑问存在)。作为UDF中使用的类的方法,Spark必须序列化该类的实例,以便在执行程序上远程使用它(UDF应用于跨执行程序JVM分布的数据)。该实例还包含名为sc(类型为SparkContext)的成员,该成员不可序列化(如错误消息所述),因此序列化失败。

工作示例(df2.show(1))有效,因为它不使用方法,而不是匿名函数,它不引用封装类,因此可以被序列化(不必序列化不可序列化的SparkContext)。

要在仍然使用命名方法(例如test)的同时解决该问题,您可以放置​​该方法:

  1. 对象中,因此无需序列化
  2. 可序列化类(一个范围为Serializable并且没有不可自行序列化的成员的类中)
  3. 您可以定义一个不是任何类方法的命名函数:

    val test: String => Int = s => s.length