在spark(scala)中修改对象的RDD

时间:2015-06-18 11:12:18

标签: scala apache-spark rdd

我有:

val rdd1: RDD[myClass]

它已被初始化,我在调试时检查了所有成员都有其默认值

如果我这样做

rdd1.foreach(x=>x.modifier())

其中modifier是myClass的成员函数,它修改了一些成员变量

执行此操作后,如果我检查RDD中的值,则表示尚未修改。

有人可以解释这里发生了什么吗? 是否可以确保在RDD中修改值?

修改

class myClass(var id:String,var sessions: Buffer[Long],var avgsession: Long)  {
    def calcAvg(){
   // calculate avg by summing over sessions and dividing by legnth
   // Store this average in avgsession
    }
}

如果我

,avgsession属性不会更新
myrdd.foreach(x=>x.calcAvg())

4 个答案:

答案 0 :(得分:8)

RDD是不可变的,在它包含的对象上调用变异方法不会产生任何影响。

获得所需结果的方法是生成<div id="first-result"></div> <div id="second-result"></div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>的新副本,而不是修改实例:

MyClass

现在你仍然无法更新rdd1,但你可以获得将包含更新实例的rdd2:

case class MyClass(id:String, avgsession: Long) {
    def modifier(a: Int):MyClass = 
       this.copy(avgsession = this.avgsession + a) 
}

答案 1 :(得分:1)

此问题的答案与此处最初接受的答案相比略有细微​​差别。原始答案仅对于未缓存在内存中的数据是正确的。缓存在内存中的RDD数据也可以在内存中进行更改,即使RDD被认为是不可变的,这些更改也将保留。考虑以下示例:

val rdd = sc.parallelize(Seq(new mutable.HashSet[Int]()))
rdd.foreach(_+=1)
rdd.collect.foreach(println)

如果运行该示例,您将得到Set()作为结果,就像原始答案状态一样。

但是,如果要通过缓存调用运行完全相同的内容:

val rdd = sc.parallelize(Seq(new mutable.HashSet[Int]()))
rdd.cache
rdd.foreach(_+=1)
rdd.collect.foreach(println)

现在结果将打印为Set(1)。因此,这取决于是否将数据缓存在内存中。如果spark是从源重新计算或从磁盘上的序列化副本读取,则它将始终重置回原始对象,并且看起来是不可变的,但如果不是从序列化形式加载,则该突变实际上会保留。

答案 2 :(得分:0)

我观察到,在使用spark / yarn运行时调用RDD.persist之后,像你这样的代码会起作用。这可能是不受支持/意外的行为,你应该避免它 - 但这是一个可能有助于紧急的解决方法。我正在运行1.5.0版本。

答案 3 :(得分:0)

对象是不可变的。通过使用map,您可以遍历rdd并返回一个新的。

val rdd2 = rdd1.map(x=>x.modifier())