我阅读了map和mapPartitions之间的理论差异,&很清楚何时在各种情况下使用它们。
但我下面描述的问题更多是基于GC活动&内存(RAM)。请阅读下面的问题: -
=>我写了一个map函数来将Row转换为String。因此,RDD [org.apache.spark.sql.Row]的输入将映射到RDD [String]。但是使用这种方法,将为RDD的每一行创建地图对象。因此,创建如此大量的对象可能会增加GC活动。
=>为了解决上述问题,我想到了使用mapPartitions。因此,该对象的数量变得等于分区的数量。 mapPartitions将Iterator作为输入,并接受返回和java.lang.Iterable。但大多数Iterable,如Array,List等都在内存中。那么,如果我有大量数据,那么以这种方式创建Iterable会导致内存不足吗?或者是否有任何其他集合(java或scala)应该在这里使用(如果内存开始填充,溢出到磁盘)?或者我们应该只使用mapPartitions以防RDD完全在内存中?
提前致谢。任何帮助将不胜感激。
答案 0 :(得分:2)
如果您考虑JavaRDD.mapPartitions
需要FlatMapFunction
(或某些变体,例如DoubleFlatMapFunction
),预计会返回Iterator
而不是Iterable
。如果收集的内容很懒,那么你就没什么可担心的了。
RDD.mapPartitions
从Iterator
到Iterator
执行功能。
如果您使用参考数据,我可以将mapPartitions
替换为map
并使用静态成员来存储数据。这将具有相同的足迹,并且更容易编写。
答案 1 :(得分:1)
回答有关mapPartition(f:Iterator => Iterator)的问题。它是懒惰的,并且不将整个分区保存在mem中。 Spark将使用此(我们可以认为它是FP术语中的Functor)Iterator => Iterator函数,并将其重新编译为自己的代码以执行。如果分区太大,它将在下一个随机播放点之前溢出到磁盘。所以不用担心
需要提及的一件事是,您可以通过执行以下操作来强制函数将数据具体化为内存:
rdd.mapPartition(
partitionIter => {
partitionIter.map(do your logic).toList.toIterator
}
)
toList
将强制Spark将整个分区的数据具体化为mem,因此请注意这一点,因为toList
之类的操作会破坏功能链的惰性。