我现在开始学习使用Scala的spark。我正在处理的问题需要我读取一个文件,拆分某个字符的每一行,然后过滤其中一列与谓词匹配的行,最后删除一列。因此,基本的,天真的实现是一个地图,然后是一个过滤器,然后是另一个地图。
这意味着要经历3次收藏,这对我来说似乎是不合理的。所以我尝试用一个集合替换它们(将部分函数作为参数的集合)。令我惊讶的是,这让它运行得慢得多。我在常规的Scala集合上尝试了本地化;正如预期的那样,后一种做法要快得多。
那为什么呢?我的想法是地图和过滤器和地图不是按顺序应用,而是混合成一个操作;换句话说,当一个动作强制评估时,将检查列表的每个元素,并执行待处理的操作。是对的吗 ?但即便如此,为什么收集表现如此糟糕呢?
编辑:显示我想要做的代码示例:
天真的方式:
sc.textFile(...).map(l => {
val s = l.split(" ")
(s(0), s(1))
}).filter(_._2.contains("hello")).map(_._1)
收集方式:
sc.textFile(...).collect {
case s if(s.split(" ")(0).contains("hello")) => s(0)
}
答案 0 :(得分:4)
答案在于collect
:
/**
* Return an RDD that contains all matching values by applying `f`.
*/
def collect[U: ClassTag](f: PartialFunction[T, U]): RDD[U] = withScope {
val cleanF = sc.clean(f)
filter(cleanF.isDefinedAt).map(cleanF)
}
正如您所看到的,它与filter
- > map
的序列相同,但效率较低。
在scala中,isDefinedAt
和[{1}}评估apply
部分的PartialFunction
和if
方法。
所以,在你的"收集"示例split
将针对每个输入元素执行两次。