我有一个来自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的序列化而另一路径不需要。有人可以开导我吗?
答案 0 :(得分:1)
test
是包含类的方法(在帖子中没有显示,但毫无疑问存在)。作为UDF中使用的类的方法,Spark必须序列化该类的实例,以便在执行程序上远程使用它(UDF应用于跨执行程序JVM分布的数据)。该实例还包含名为sc
(类型为SparkContext
)的成员,该成员不可序列化(如错误消息所述),因此序列化失败。
工作示例(df2.show(1)
)有效,因为它不使用方法,而不是匿名函数,它不引用封装类,因此可以被序列化(不必序列化不可序列化的SparkContext
)。
要在仍然使用命名方法(例如test
)的同时解决该问题,您可以放置该方法:
Serializable
并且没有不可自行序列化的成员的类中)您可以定义一个不是任何类方法的命名函数:
val test: String => Int = s => s.length