使用var过滤RDD的意外行为

时间:2016-07-18 08:22:19

标签: scala apache-spark

我在代码中遇到了一个奇怪的错误,在调试时我能够改进问题。问题是,当我使用var变量过滤var RDD,然后将过滤结果存储在相同的RDD中时,RDD会正确更新。 问题是,在我更新var变量后,我用来过滤结果我自动再次过滤!

示例代码:

var filter = 5
var a1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9))
a1 = a1.filter(t => !t.equals(filter))
a1.foreach(println) // result is: 1-9 without 5
filter = filter + 1
a1.foreach(println) // result is: 1-9 without 6

为什么会这样?这样做的规则是什么,不会导致我的代码中的错误?

3 个答案:

答案 0 :(得分:6)

Spark延迟评估。执行a1.filter后,您会收到FilteredRDD,但实际上您并未在该时间点获得计算结果。只有当您使用foreach请求并对转换采取操作时,才会调用转换。

除了延迟过滤,lambda表达式还会捕获变量,而不是值。这意味着当您更新filter时,捕获的lambda中的相同变量将从5更新为6,然后再次过滤它会生成具有更新值的所有元素。

答案 1 :(得分:3)

这是因为a1包含完整的DAG。而foreach是一个动作,它将触发DAG获得结果。

scala> var a1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9))
a1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[4] at parallelize at <console>:21

scala> a1.toDebugString
res5: String = (4) ParallelCollectionRDD[4] at parallelize at <console>:21 []

scala> a1 = a1.filter(t => !t.equals(filter))
a1: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[5] at filter at <console>:25


scala> a1.toDebugString
res6: String = 
(4) MapPartitionsRDD[5] at filter at <console>:25 []
 |  ParallelCollectionRDD[4] at parallelize at <console>:21 []

因此,无论何时使用foreach打印rdd,都会在关闭时获取过滤器值,并通过计算DAG获得结果。

filter = 6
a1.foreach(println) // will filter 6
filter = 9
a1.foreach(println) // will filter 9

答案 2 :(得分:1)

试试这些,看看会发生什么:

var filter = 5
var a1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9))
a1 = sc.parallelize(a1.filter(t => !t.equals(filter)).collect())
a1.foreach(println)
filter = filter + 1
a1.foreach(println)

这也是:

var filter = 5
var a1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9))
a1 = a1.filter(t => !t.equals(filter)).cache()
a1.foreach(println)
filter = filter + 1
a1.foreach(println)

希望这些会让你更多思考!