collect
方法,可以使用部分函数在一次遍历中执行filter-map
操作。Spark Dataset
上有等效的操作吗?我想出于两个原因:- 语法简洁
- 它将
filter-map
样式操作减少为单次遍历(尽管在Spark中,我猜测有优化可以为您发现这些内容)
Some
中的那些)。val input = Seq(Some(3), None, Some(-1), None, Some(4), Some(5))
Method 1 - collect
input.collect {
case Some(value) => value * 2
}
// List(6, -2, 8, 10)
collect
这个方法语法很简洁,只需要一次遍历即可完成。
方法2 - filter-map
input.filter(_.isDefined).map(_.get * 2)
我可以将这种模式应用到Spark中,因为数据集和数据框具有类似的方法。
但我不太喜欢这种方法,因为`isDefined`和`get`看起来像是代码异味。这里存在着一个隐含的假设,即map函数仅接收`Some`。编译器无法验证这一点。在一个更大的例子中,开发者很难发现这个假设,例如开发者可能会交换过滤和映射操作的顺序,而不会得到语法错误。
第三种方法-`fold*`操作
input.foldRight[List[Int]](Nil) {
case (nextOpt, acc) => nextOpt match {
case Some(next) => next*2 :: acc
case None => acc
}
}
我没有足够的Spark使用经验,不知道fold是否有一个等效的函数,因此这可能有点离题。
总之,模式匹配、折叠模板和列表重建都混杂在一起,很难阅读。
因此,总的来说,我认为collect
语法最好,希望Spark也有类似的东西。
collect
方法定义在RDD
和Dataset
上,用于将数据实现化到驱动程序中。尽管没有类似于集合API的collect
方法,但您的直觉是正确的:由于两个操作都是惰性评估的,因此引擎有机会优化这些操作并将它们链接起来,以便以最大的局部性执行。 - stefanobaghino