spark foreach与foreachPartition
每个partition中iterator时行迭代的处理,通过用户传入的function对iterator进行内容的处理
一:foreach的操作:
Foreach中,传入一个function,这个函数的传入参数就是每个partition中,每次的foreach得到的一个rdd的kv实例,也就是具体的内容
这种处理你并不知道这个iterator的foreach什么时候结果,只能是在foreach过程中,你得到一条数据,就处理一条数据
由下面的代码可以看出,foreach操作是直接调用了partition中数据的foreach操作
def foreach(f:Unit):Unit=withScope{
val cleanF=sc.clean(f)
sc.runJob(this,(iter:Iterator[t])=> iter.foreach(cleanF))
}
示例说明:
val list = new ArrayBuffer()
Rdd.foreach(record=>
list+=record
if(list.size>=10000){
list.flush
}
)
上面的这段示例代码,如果会存在一个问题,迭代的最后,list的结果可能还没有达到10000条,这个时候,你在内部处理的flush部分就不会执行,也就是迭代的最后如果没有迭代达到10000条的数据就会丢失,所以在foreach中,一般就是拿到一条数据进行处理
Rdd.foreach(
record._1 == a
return)
foreachPartition 操作
这个函数也是根据传入的function进行处理,但是不同之处再有这里function传入的参数是一个partition对应数据的iterator
而不是直接使用iterator的foreach,这种情况下,如果是上面foreach的示例代码中list这个片段在这个actition中就能够正常的去处理
def foreachPartition(f:Iterrator[T]=>Unit):Unit=withScope{
val cleanF=sc.clean(f)
sc.runJob(this,(iter:Itertor[T]=>cleanF(iter)))
}
示例
val list = new ArrayBuffer
rdd.foreachPartition(it=>{
it.foreach(r=>{
list+=r
if(list.size>10000)
flush
})
if(list.size>0)
flush
})
关于源码
可以看到方法通过clean操作(清理闭包,为序列化和网络传输做准备),进行了一次匿名函数的封装
针对foreach方法,是我们的方法被传入了迭代器foreach(每个元素执行一次函数)
而对于foreachPartition方法是迭代器被传入了我们的方法(每个分区执行一次函数,我们获取迭代器后需要自行进行迭代处理)