平面图是否比filter + map具有更好的性能?

时间:2019-06-25 20:00:35

标签: scala apache-spark

我有一个很大的数据集(一亿多条记录,其中有100列),我正在使用spark处理。我正在将数据读取到spark数据集中,我想过滤该数据集并将其字段的子集映射到case类。

代码看起来有些相似

case class Subset(name:String,age:Int)
case class Complete(name:String,field1:String,field2....,age:Int)

val ds = spark.read.format("csv").load("data.csv").as[Complete]

#approach 1
ds.filter(x=>x.age>25).map(x=> Subset(x.name,x.age))

#approach 2
ds.flatMap(x=>if(x.age>25) Seq(Subset(x.name,x.age)) else Seq.empty)

哪种方法更好?关于如何使此代码更具性能的任何其他提示?

谢谢!

修改

我进行了一些测试以比较运行时,方法2看起来相当快,我用于获取运行时的代码如下,

val subset = spark.time {
   ds.filter(x=>x.age>25).map(x=> Subset(x.name,x.age))
}

spark.time {
   subset.count()
}

and 

val subset2 = spark.time {
   ds.flatMap(x=>if(x.age>25) Seq(Subset(x.name,x.age)) else Seq.empty)
}

spark.time {
   subset2.count()
}

2 个答案:

答案 0 :(得分:3)

更新:我的原始答案包含一个错误: Spark 确实支持SeqflatMap(并将结果转换回变成Dataset)。抱歉造成混乱。我还添加了有关改善分析性能的更多信息。

更新2 :我想念您使用的是Dataset而不是RDD(谢谢!)。这不会严重影响答案。

Spark 是一个分布式系统,可在多个节点之间划分数据并并行处理数据。在效率方面,导致运行过程中重新分区(需要在节点之间传输数据)的操作在运行时方面比在位修改要昂贵得多。另外,您应注意,仅对数据进行转换的操作(例如filtermapflatMap等)仅被存储,并且直到执行执行 action 操作(例如reducefoldaggregate等)。因此,无论哪种情况,任何一种选择实际上都不会做。

当对这些转换的结果执行操作时,我希望filter操作会更加高效:它仅处理通过谓词的数据(使用随后的map操作) x=>x.age>25(通常写为_.age > 25)。尽管filter似乎创建了一个中间集合,但它执行lazilly。结果, Spark 似乎将filtermap操作融合在一起。

坦率地说,您的flatMap操作是可怕的。它会强制处理,创建序列并随后对每个数据项进行展平,这肯定会增加总体处理量。

也就是说,提高分析性能的最好方法是控制分区,以便在尽可能多的节点上大致均匀地划分数据。最好参考this guide

答案 1 :(得分:-1)

根据语法的逻辑判断,第一种方法应使用较少的空间,因为flatMap扩展到了.map()。flatten,这两个参数的大小均相等。它可以在Scala REPL中编译为相同的Java字节码(编辑:当使用pet示例时,显然不能补偿用相当大的数据进行实际测试的代价)。

相关问题