web-dev-qa-db-fra.com

Itérer des lignes et des colonnes dans le cadre de données Spark

J'ai le dataframe Spark suivant qui est créé dynamiquement:

val sf1 = StructField("name", StringType, nullable = true)
val sf2 = StructField("sector", StringType, nullable = true)
val sf3 = StructField("age", IntegerType, nullable = true)

val fields = List(sf1,sf2,sf3)
val schema = StructType(fields)

val row1 = Row("Andy","aaa",20)
val row2 = Row("Berta","bbb",30)
val row3 = Row("Joe","ccc",40)

val data = Seq(row1,row2,row3)

val df = spark.createDataFrame(spark.sparkContext.parallelize(data), schema)

df.createOrReplaceTempView("people")
val sqlDF = spark.sql("SELECT * FROM people")

Maintenant, je dois itérer chaque ligne et colonne dans sqlDF pour imprimer chaque colonne, voici ma tentative:

sqlDF.foreach { row =>
  row.foreach { col => println(col) }
}

row est de type Row, mais n'est pas itérable, c'est pourquoi ce code génère une erreur de compilation dans row.foreach. Comment itérer chaque colonne dans Row?

12
ps0604

Vous pouvez convertir Row en Seq avec toSeq. Une fois passé à Seq, vous pouvez le parcourir comme d'habitude avec foreach, map ou ce dont vous avez besoin

    sqlDF.foreach { row => 
           row.toSeq.foreach{col => println(col) }
    }

Sortie:

Berta
bbb
30
Joe
Andy
aaa
20
ccc
40
6
SCouto

Considérez que vous avez une Dataframe comme ci-dessous

val df = Seq(
          ("Andy","aaa", 20),     
          ("Berta","bbb", 30),
          ("Joe","ccc", 40)).toDF("name","sector","age")

Pour boucler votre Dataframe et extraire les éléments du Dataframe , df.foreach ne vous aidera pas directement. Pour le mettre en œuvre, vous pouvez choisir l'une des approches ci-dessous.

Approche 1 - Boucle avec rdd

Utilisez rdd.collect en plus de votre Dataframe . La variable row contiendra chaque ligne de Dataframe de type rdd. Pour obtenir chaque élément d'une ligne, utilisez row.mkString(",") qui contiendra la valeur de chaque ligne sous forme de valeurs séparées par des virgules. En utilisant la fonction split (fonction intégrée), vous pouvez accéder à chaque valeur de colonne de rdd rangée avec index.

for (row <- df.rdd.collect)
{   
    var name = row.mkString(",").split(",")(0)
    var sector = row.mkString(",").split(",")(1)
    var age = row.mkString(",").split(",")(2)   
}

Approche 2 - Utiliser où et sélectionner

Vous pouvez directement utiliser where et select qui effectuera une boucle interne et trouvera les données. Puisqu'il ne devrait pas lancer l'exception Index hors limite, une condition if est utilisée

if(df.where($"name" === "Andy").select(col("name")).collect().length >= 1)
    name = df.where($"name" === "Andy").select(col("name")).collect()(0).get(0).toString

Approche 3 - Utilisation de tables temporaires

Vous pouvez enregistrer une image de données comme étant tentante, qui sera stockée dans la mémoire de spark. Ensuite, vous pouvez utiliser une requête select comme une autre base de données pour interroger les données, puis collecter et enregistrer dans une variable.

df.registerTempTable("student")
name = sqlContext.sql("select name from student where name='Andy'").collect()(0).toString().replace("[","").replace("]","")
6
Sarath Avanavu

Vous devriez utiliser mkString sur votre Row:

sqlDF.foreach { row =>
  println(row.mkString(",")) 
}

Mais notez que cela sera imprimé dans les machines virtuelles JVM des exécuteurs, donc normalement, vous ne verrez pas la sortie (sauf si vous travaillez avec maître = local)

2
Raphael Roth

sqlDF.foreach ne fonctionne pas pour moi mais l'approche 1 de @Sarath Avanavu answer fonctionne, mais elle jouait aussi parfois avec l'ordre des enregistrements. 

J'ai trouvé un autre moyen qui fonctionne

df.collect().foreach { row =>
   println(row.mkString(","))
}
0
Naresh Joshi