web-dev-qa-db-ja.com

Spark:リストへのRDD

私はRDD構造を持っています

RDD[(String, String)]

また、2つのリスト(rddの各次元に1つ)を作成します。

Rdd.foreach()を使用して2つのListBufferを埋めてからリストに変換しようとしましたが、反復後にBufferListsが空になるため、各ノードが独自のListBufferを作成すると思います。どうすればいいですか?

編集:私のアプローチ

val labeled = data_labeled.map { line =>
  val parts = line.split(',')
  (parts(5), parts(7))
}.cache()

var testList : ListBuffer[String] = new ListBuffer()

labeled.foreach(line =>
  testList += line._1
)
  val labeledList = testList.toList
  println("rdd: " + labeled.count)
  println("bufferList: " + testList.size)
  println("list: " + labeledList.size)

結果は次のとおりです。

rdd: 31990654
bufferList: 0
list: 0
14
bill

本当に2つのLists-を作成したい場合は、すべての分散データをドライバーアプリケーションに収集する必要があります(遅延またはOutOfMemoryErrorのリスク)-collectそして、結果に対して単純なmap操作を使用します。

val list: List[(String, String)] = rdd.collect().toList
val col1: List[String] = list.map(_._1)
val col2: List[String] = list.map(_._2)

または、RDDを2つに「分割」したい場合RDDs-データを収集せずにかなり似ています:

rdd.cache() // to make sure calculation of rdd is not repeated twice
val rdd1: RDD[String] = rdd.map(_._1)
val rdd2: RDD[String] = rdd.map(_._2)

3番目の選択肢は、最初にこれら2つのRDDにマッピングしてから、それぞれを収集することですが、最初のオプションと大差はなく、同じリスクと制限に悩まされます。

17
Tzach Zohar

Tzach Zoharの答えの代替として、リストでunzipを使用できます。

scala> val myRDD = sc.parallelize(Seq(("a", "b"), ("c", "d")))
myRDD: org.Apache.spark.rdd.RDD[(String, String)] = ParallelCollectionRDD[0] at parallelize at <console>:27

scala> val (l1, l2) = myRDD.collect.toList.unzip
l1: List[String] = List(a, c)
l2: List[String] = List(b, d)

または、keyssのvaluesおよびRDD

scala> val (rdd1, rdd2) = (myRDD.keys, myRDD.values)
rdd1: org.Apache.spark.rdd.RDD[String] = MapPartitionsRDD[1] at keys at <console>:33
rdd2: org.Apache.spark.rdd.RDD[String] = MapPartitionsRDD[2] at values at <console>:33

scala> rdd1.foreach{println}
a
c

scala> rdd2.foreach{println}
d
b
2
evan.oman