RDD の foreach と foreachPartition の違い





参考:

RDD.foreachPartition/foreach の操作
この アクション の操作では :
これら 2 つの アクションは主に、 パーティション 内の イテレータ の反復を処理するために使用 され イテレータの内容は、 ユーザーによって渡された 関数 を通じて処理されます
まず、 foreach の操作 を見てみましょう
fureach , 传入一个 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 => {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)

おすすめ

転載: blog.csdn.net/cxkaa502401673/article/details/78801728