我在代码中遇到了一个奇怪的错误,在调试时我能够改进问题。问题是,当我使用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
为什么会这样?这样做的规则是什么,不会导致我的代码中的错误?
答案 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)
希望这些会让你更多思考!