web-dev-qa-db-fra.com

Spark: RDD à la liste

J'ai une structure RDD

RDD[(String, String)]

et je veux créer 2 listes (une pour chaque dimension du rdd).

J'ai essayé d'utiliser le rdd.foreach () et de remplir deux ListBuffers, puis de les convertir en listes, mais je suppose que chaque nœud crée son propre ListBuffer car après l'itération, les BufferLists sont vides. Comment puis-je le faire ?

EDIT: ma démarche

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)

et le résultat est:

rdd: 31990654
bufferList: 0
list: 0
14
bill

Si vous voulez vraiment en créer deux Lists - ce qui signifie, vous voulez que toutes les données distribuées soient collectées dans l'application du pilote (risquant la lenteur ou OutOfMemoryError) - vous pouvez utiliser collect puis utilisez des opérations simples map sur le résultat:

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

Alternativement - si vous voulez "diviser" votre RDD en deux RDD - c'est assez similaire sans collecter les données:

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)

Une troisième alternative consiste à mapper d'abord sur ces deux RDD, puis à collecter chacun d'eux, mais ce n'est pas très différent de la première option et souffre des mêmes risques et limites.

17
Tzach Zohar

Comme alternative à la réponse de Tzach Zohar, vous pouvez utiliser unzip dans les listes:

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)

Ou keys et values sur les RDDs:

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