参考:
RDD.foreachPartition/foreach
的操作
在这个
action
的操作中
:
这两个
action
主要用于对每一个
partition
中的
iterator
时行迭代的处理
.
通过用户传入的
function
对
iterator
进行内容的处理
.
首先我们先看看
foreach
的操作
:
在
fureach
中
,
传入一个
function,
这个函数的传入參数就是每一个
partition
中
,
每次的
foreach
得到的一个
rdd
的
kv
实例
,
也就是详细的内容
,
这样的处理你并不知道这个
iterator
的
foreach
什么时候结果
,
仅仅能是
foreach
的过程中
,
你得到一条数据
,
就处理一条数据
.
由以下的红色部分能够看出
,foreach
操作是直接调用了
partition
中数据的
foreach
操作
.
def
foreach(f:
T
=>
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 => {record._1 == a return})
然后接下来看看
foreachPartition
:
这个函数也是依据传入的
function
进行处理
,
但不同处在于
,
这里
function
的传入參数是一个
partition
相应数据的
iterator.
而不是直接使用
iterator
的
foreach,
这样的情况下
,
假设是上面
foreach
的演示样例代码中
list
这个片段在这个
action
中就行正常的去处理
.
def
foreachPartition(f:
Iterator
[
T
] =>
Unit
):
Unit
=
withScope {
val
cleanF = sc.clean(f)
sc.runJob(
this
,
(iter: Iterator[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
})
最后说下这两个
action
的差别
:
Foreach
与
foreachPartition
都是在每一个
partition
中对
iterator
进行操作
,
不同的是
,foreach
是直接在每一个
partition
中直接对
iterator
运行
foreach
操作
,
而传入的
function
仅仅是在
foreach
内部使用
,
而
foreachPartition
是在每一个
partition
中把
iterator
给传入的
function,
让
function
自己对
iterator
进行处理
.
个人理解就是
foreach和foreachPartition
的参数:函数(T)的作用对象不一样,
foreach
是作用在
iterator
循环取出来的每个RDD上,
foreachPartition
是让
该
iterator
执行这个函数(T)