Scala Spark:无法将RDD元素添加到闭包内的可变HashMap中

Scala Spark:无法将RDD元素添加到闭包内的可变HashMap中,scala,hashmap,apache-spark,rdd,Scala,Hashmap,Apache Spark,Rdd,我有以下代码,其中rddMap是org.apache.spark.rdd.rdd[(String,(String,String))],而myHashMap是scala.collection.mutable.HashMap 我做了.saveAsTextFile(“temp_out”)来强制计算rddMap.map 然而,即使是println(“t”+t)正在打印东西,后来myHashMap仍然只有一个元素是我手动放在开头的(“test1”,“10”,“20”)。 rddMap中的所有内容都没有放入

我有以下代码,其中
rddMap
org.apache.spark.rdd.rdd[(String,(String,String))]
,而
myHashMap
scala.collection.mutable.HashMap

我做了
.saveAsTextFile(“temp_out”)
来强制计算
rddMap.map

然而,即使是
println(“t”+t)
正在打印东西,后来
myHashMap
仍然只有一个元素是我手动放在开头的
(“test1”,“10”,“20”)
rddMap
中的所有内容都没有放入
myHashMap

代码片段:

val myHashMap = new HashMap[String, (String, String)]
myHashMap.put("test1", ("10", "20"))
rddMap.map { t =>
  println(" t " + t)
  myHashMap.put(t._1, t._2)
}.saveAsTextFile("temp_out")

println(rddMap.count)
println(myHashMap.toString)

为什么我不能将rddMap中的元素放入我的
myHashMap

下面是一个您想要完成的工作示例

val rddMap = sc.parallelize(Map("A" -> ("v", "v"), "B" -> ("d","d")).toSeq)
// Collects all the data in the RDD and converts the data to a Map
val myMap = rddMap.collect().toMap
myMap.foreach(println)
输出:

(A,(v,v))  
(B,(d,d))
下面是与您发布的代码类似的代码

rddMap.map { t=> 
  println("t" + t)
  newHashMap.put(t._1, t._2)
  println(newHashMap.toString) 
}.collect
这是Spark shell向上述代码的输出

t(A,(v,v))  
Map(A -> (v,v), test1 -> (10,20))  
t(B,(d,d))  
Map(test1 -> (10,20), B -> (d,d))

在我看来,Spark复制了您的HashMap,并将元素添加到复制的映射中。

Spark今天并不真正支持您尝试执行的操作

请注意,每个用户定义的函数(例如,您在
map()
中添加的函数)都是一个闭包,它被序列化并推送到每个执行器

因此,此
map()
中的所有内容都会被序列化并四处传输:

.map{ t =>
  println(" t " + t)
  myHashMap.put(t._1, t._2)
}
基本上,您的
myHashMap
将被复制到每个执行者,每个执行者将更新自己的
HashMap
版本。这就是为什么在执行结束时,驱动程序中的
myHashMap
永远不会被更改。(驱动程序是管理/协调Spark作业的JVM。它是定义SparkContext的地方。)

为了将驱动程序中定义的结构推送到所有执行者,您需要
广播它们(参见链接)。请注意,广播的变量是只读的,所以同样,在这里使用广播对您没有帮助

另一种方法是使用
累加器
,但我觉得这些累加器更适合汇总数值,比如求和、求最大、求最小等。也许您可以看看创建一个扩展
累加器参数
的自定义累加器。见链接


回到最初的问题,如果您想收集驱动程序的值,目前最好的方法是转换RDD,直到它们成为一个小的、可管理的元素集合,然后您
collect()
此最终/小型RDD。

您是否在群集模式下使用
Spark
?我尝试了群集模式和本地模式,两者都无效谢谢!如果我在集群上运行,我需要广播myMap吗?您需要广播共享变量,是的。但实际上,如果可能的话,您应该避免使用@ColinMC的第一种方法,