我是Scala的新手。我在Spark上执行下面的代码:
scala> for(line <- sc.textFile("hdfs://ip:8020/property.conf"))
{
val c = line.split("=")
SparkConf.set(c(0), c(1))
//println(c(0)+" "+c(1)) //Commented
}
如果我删除评论的部分并评论SparkConf.set(c(0), c(1))
,那么它可以正常工作并显示数据。
但在这种情况下,我想在运行时将参数设置为 SparkConf 。 但它让我错误
org.apache.spark.SparkException:任务不可序列化
请建议我做点什么。
答案 0 :(得分:2)
理解spark的一个非常重要的事情是它是一个分布式环境。
名称RDD
是Resilient Distributed Datasets
的缩写。 spark RDD中的项目通常分为partitions
,它们分布在Spark集群中的各个不同节点上。
当你调用yourRdd.map(a => a.toString)
之类的东西时,这个RDD的map
实现知道它必须首先将这个a => a.toString
函数包装在一个闭包中,然后序列化该闭包然后发送它到具有此partitions
RDD
的所有节点。结果的实际计算发生在那些节点上。
所以......当你处理RDD
时,请确保你不要将分发感知RDD
api与普通的Scala api混淆/混合。
编写一段代码的推荐方法是,
val yourRdd = sc.textFile("hdfs://ip:8020/property.conf"))
yourRdd.foreach(line =>
val c = line.split("=")
println(c(0) + " " + c(1))
)
在SparkConf.set(c(0), c(1))
行中,SparkConf
是class
,您通常无法序列化classes
。你也不能在set
上调用成员函数class SparkConf
。您需要创建classes
的实例。另外SparkConf
碰巧是一个没有实现可序列化接口的类,因此即使SparkConf
的实例也不可序列化。
通常情况下,您不应该使用spark RDD来创建SparkConf
,因为如果没有SparkContext
而RDD将不存在,而SparkConf
又需要初始化val mySparkConf = new SparkConf()
val yourRdd = sc.textFile("hdfs://ip:8020/property.conf"))
val yourList = yourRdd.foreach(line =>
val c = line.split("=")
).collect.toList
yourList.foreach(c => mySparkConf.set(c(0), c(1)))
。
但是对于这种情况,我们可以说你需要这样做...然后你首先从你的RDD获得一个普通的scala列表然后用它来创建你的SparkConf。
.fixed-table-body