正常情况下我们使用map方法就足够了,一是使用简单,二是较为安全,mapPartitions在数据量很大的时候相当容易OOM,甚至是导致频繁GC,当然如果你资源足够且map方法对于你确实是效率不佳,那可以考虑使用mapPartitions
首先先要知道mapPartitions
和map
有什么区别,map是直接处理单一的数据并返回,而mapPartitions是处理一个分区下的所有数据,并且它拿到的处理返回值必须
是一个容器的迭代器
下面开一个实例
object Test {
def main(args: Array[String]): Unit = {
val session = SparkSession.builder().master("local[*]").appName("loadTest").getOrCreate()
session.sparkContext.setLogLevel("ERROR")
val sc = session.sparkContext
val a = sc.parallelize(1 to 5)
val result = a.mapPartitions(iter => {
val res:scala.collection.mutable.ListBuffer[Int] = scala.collection.mutable.ListBuffer[Int]()
while (iter.hasNext)
{
val cur = iter.next;
res.insert(0,cur*3) ;
}
//返回容器的迭代器
res.iterator
})
println(result.collect().mkString(","))
session.stop()
}
}
总体来说mapPartitions方法使用不困难,但是大家在实际开发中不要使用样例中的这种写法,这种写法是为了大家容易吸收,虽然我用了可变List,避免了不可变List的重复创建开销,不过在实际开发中,有一种高效的写法
object Test {
def main(args: Array[String]): Unit = {
val session = SparkSession.builder().master("local[*]").appName("loadTest").getOrCreate()
session.sparkContext.setLogLevel("ERROR")
val sc = session.sparkContext
val a = sc.parallelize(1 to 5)
val result = a.mapPartitions(r => new CustomIterator(r))
println(result.collect().mkString(","))
session.stop()
}
}
class CustomIterator(iter: Iterator[Int]) extends Iterator[Int] {
def hasNext : Boolean = {
iter.hasNext
}
def next : Int= {
val cur = iter.next
cur
}
}