web-dev-qa-db-ja.com

RDD Aggregate in spark

私はApache Spark学習者であり、RDD action aggregateに遭遇しました。ここでコードの以下の結果にどのように到達したのか、ステップごとに詳細に

RDD input = {1,2,3,3}

RDD Aggregate function :

rdd.aggregate((0, 0))
((x, y) =>
(x._1 + y, x._2 + 1),
(x, y) =>
(x._1 + y._1, x._2 + y._2))

output : {9,4}

ありがとう

15
Lijju Mathew

何が起こっているのかわからない場合は、タイプに従うのが最善です。簡潔にするために暗黙のClassTagを省略すると、次のようなものから始めます。

_abstract class RDD[T] extends Serializable with Logging 

def aggregate[U](zeroValue: U)(seqOp: (U, T) ⇒ U, combOp: (U, U) ⇒ U): U 
_

追加のパラメーターをすべて無視すると、aggregateは_RDD[T]_からUにマップされる関数であることがわかります。これは、入力RDDの値のタイプが出力値のタイプと同じである必要がないことを意味します。したがって、たとえばreduceとは明らかに異なります。

_def reduce(func: (T, T) ⇒ T): T 
_

またはfold

_def fold(zeroValue: T)(op: (T, T) => T): T
_

foldと同様に、aggregateにはzeroValueが必要です。どうやって選ぶの? combOpに関してアイデンティティ(中立)要素でなければなりません。

また、2つの機能を提供する必要があります。

  • _(U, T)_からseqOpにマップするU
  • _(U, U)_からcombOpにマップするU

この署名に基づいて、seqOpのみが未加工データにアクセスできることがすでにわかるはずです。タイプUの値を取り、タイプTの別の値を取り、タイプUの値を返します。あなたの場合、それは次の署名を持つ関数です

_((Int, Int), Int) => (Int, Int) 
_

この時点で、おそらく何らかの折り畳み操作に使用されていると思われます。

2番目の関数は、U型の2つの引数を取り、U型の値を返します。前に述べたように、元のデータには影響せず、seqOpによって既に処理された値に対してのみ動作できることは明らかです。あなたの場合、この関数には次のようなシグネチャがあります。

_((Int, Int), (Int, Int)) => (Int, Int) 
_

それでは、どうすればそれらすべてをまとめることができますか?

  1. 最初に、各パーティションは標準の _Iterator.aggregate_ を使用して集約され、それぞれzeroValueseqOpおよびcombOpzseqopおよびcombopとして渡されます。内部で使用される InterruptibleIteratoraggregateをオーバーライドしないため、単純な foldLeft(zeroValue)(seqOp) として実行する必要があります。

  2. 各パーティションから収集された次の部分的な結果は、combOpを使用して集約されます

入力RDDに次の値の分布を持つ3つのパーティションがあると仮定します。

  • Iterator(1, 2)
  • Iterator(2, 3)
  • Iterator()

絶対順序を無視した実行は、次のようなものと同等になると期待できます。

_val seqOp = (x: (Int, Int), y: Int) => (x._1 + y, x._2 + 1)
val combOp = (x: (Int, Int), y: (Int, Int)) => (x._1 + y._1, x._2 + y._2)

Seq(Iterator(1, 2), Iterator(3, 3), Iterator())
  .map(_.foldLeft((0, 0))(seqOp))
  .reduce(combOp)
_

単一パーティションのfoldLeftは次のようになります。

_Iterator(1, 2).foldLeft((0, 0))(seqOp)
Iterator(2).foldLeft((1, 1))(seqOp)
(3, 2)
_

すべてのパーティションに

_Seq((3,2), (6,2), (0,0))
_

組み合わせた結果は次のとおりです。

_(3 + 6 + 0, 2 + 2 + 0)
(9, 4)
_

一般的に、これは一般的なパターンであり、Spark中立値、パーティションごとの値を処理するために使用される関数、異なるパーティションからの部分集約をマージするために使用される関数。例は次のとおりです。

  • aggregateByKey
  • ユーザー定義の集計関数
  • Aggregators on Spark Datasets
23
zero323

あなたの参照のための私の理解はここにあります:

2つのノードがあるとします。1つは最初の2つのリスト要素{1,2}の入力を受け取り、もう1つは{3、3}を受け取ります。 (ここのパーティションは便宜上のものです)

最初のノード: "(x、y>(x._1 + y、x._2 + 1))=="、最初のxは与えられた(0,0)であり、yは最初の要素1、出力(0 + 1、0 + 1)があり、2番目の要素y = 2、出力(1 + 2、1 + 1)、つまり(3、2)

2番目のノードでは、同じ手順が並行して行われ、(6、2)が得られます。

"(x、y>(x._1 + y._1、x._2 + y._2))=="、2つのノードをマージするように指示すると、(9,4 )


注目に値するものの1つは、(0,0)が実際に結果の長さ(rdd)+1回に追加されることです。

"scala> rdd.aggregate((1,1))((x、y)=>(x._1 + y、x._2 + 1)、(x、y)= >(x._1 + y._1、x._2 + y._2))res1:(Int、Int)=(14,9) "

4
Yuanxu Xu