Comment imprimer le contenu de RDD?

124

J'essaie d'imprimer le contenu d'une collection sur la console Spark.

J'ai un type:

linesWithSessionId: org.apache.spark.rdd.RDD[String] = FilteredRDD[3]

Et j'utilise la commande:

scala> linesWithSessionId.map(line => println(line))

Mais ceci est imprimé:

res1: org.apache.spark.rdd.RDD [Unit] = MappedRDD [4] sur la carte à: 19

Comment puis-je écrire le RDD sur la console ou l'enregistrer sur le disque afin de pouvoir afficher son contenu?

ciel bleu
la source
1
Salut! avez-vous lu les commentaires sur la réponse, acceptés par vous? Cela semble trompeur
dk14
2
@ dk14 d'accord, j'ai réaffecté la réponse acceptée
blue-sky
RDD sont relégués comme citoyens de seconde zone, vous devriez utiliser DataFrame et la showméthode.
Thomas Decaux

Réponses:

235

Si vous souhaitez afficher le contenu d'un RDD, une méthode consiste à utiliser collect():

myRDD.collect().foreach(println)

Ce n'est pas une bonne idée, cependant, lorsque le RDD a des milliards de lignes. Utilisez take()pour n'en prendre que quelques-uns à imprimer:

myRDD.take(n).foreach(println)
Oussama
la source
1
si j'utilise foreach sur RDD (qui contient des millions de lignes) pour écrire le contenu dans HDFS en tant que fichier unique, fonctionnera-t-il sans aucun problème sur le cluster?
Shankar
La raison pour laquelle je n'utilise pas saveAsTextFilesur RDD est que j'ai besoin d'écrire le contenu RDD dans plus d'un fichier, c'est pourquoi j'utiliseforeach
Shankar
Si vous souhaitez enregistrer dans un seul fichier, vous pouvez fusionner votre RDD en une seule partition avant d'appeler saveAsTextFile, mais encore une fois, cela peut causer des problèmes. Je pense que la meilleure option est d'écrire dans plusieurs fichiers en HDFS, puis d'utiliser hdfs dfs --getmerge afin de fusionner les fichiers
Oussama
vous avez dit que lorsque vous utilisez foreach sur un RDD, il le conservera dans la RAM du pilote, la déclaration est-elle correcte? parce que ce que j'ai compris, c'est que foreach fonctionnera sur chaque travailleur [cluster] et non sur le pilote.
Shankar
saveAsTextFile écrira un fichier par partition, ce que vous voulez (plusieurs fichiers). Sinon, comme le suggère Oussama, vous pouvez faire rdd.coalesce (1) .saveAsTextFile () pour obtenir un fichier. Si le RDD a trop peu de partitions à votre goût, vous pouvez essayer rdd.repartition (N) .saveAsTextFile ()
corne de brume
49

La mapfonction est une transformation , ce qui signifie que Spark n'évaluera pas réellement votre RDD jusqu'à ce que vous exécutiez une action dessus.

Pour l'imprimer, vous pouvez utiliser foreach(qui est une action):

linesWithSessionId.foreach(println)

Pour l'écrire sur le disque, vous pouvez utiliser l'une des saveAs...fonctions (actions fixes) de l' API RDD

fedragon
la source
6
Vous devez collectpeut-être mentionner pour que le RDD puisse être imprimé dans la console.
zsxwing
1
foreachlui-même "matérialisera" d'abord le RDD puis s'exécutera printlnsur chaque élément, ce collectn'est donc pas vraiment nécessaire ici (bien que vous puissiez l'utiliser, bien sûr) ...
fedragon
5
En fait sans collect (), avant foreach, je ne peux rien voir sur la console.
Vittorio Cozzolino
3
En fait, cela fonctionne parfaitement dans mon shell Spark, même dans la version 1.2.0. Mais je pense que je sais d'où vient cette confusion: la question d'origine demandait comment imprimer un RDD sur la console Spark (= shell), donc j'ai supposé qu'il exécuterait un travail local, auquel cas cela foreachfonctionne bien. Si vous exécutez un travail sur un cluster et que vous souhaitez imprimer votre rdd, vous devez collect(comme indiqué par d'autres commentaires et réponses) afin qu'il soit envoyé au pilote avant printlnson exécution. Et utiliser takecomme suggéré par Oussama pourrait être une bonne idée si votre RDD est trop gros.
fedragon
6
La réponse ci-dessus est mauvaise. Vous devriez le rejeter. Foreach n'imprimera pas sur la console, il imprimera sur vos nœuds de travail. Si vous n'avez qu'un seul nœud, foreach fonctionnera. Mais si vous n'avez qu'un seul nœud, pourquoi utilisez-vous Spark? Utilisez simplement SQL awk, ou Grep, ou quelque chose de beaucoup plus simple. Je pense donc que la seule réponse valable est la collecte. Si la collecte est trop importante pour vous et que vous ne voulez qu'un échantillon, utilisez des fonctions de prise ou de tête ou similaires comme décrit ci-dessous.
eshalev
12

Si vous l'exécutez sur un cluster, il printlnne sera pas imprimé dans votre contexte. Vous devez apporter les RDDdonnées à votre session. Pour ce faire, vous pouvez le forcer sur la baie locale, puis l'imprimer:

linesWithSessionId.toArray().foreach(line => println(line))
Noé
la source
12

Vous pouvez convertir votre RDDen un DataFramealors show()il.

// For implicit conversion from RDD to DataFrame
import spark.implicits._

fruits = sc.parallelize([("apple", 1), ("banana", 2), ("orange", 17)])

// convert to DF then show it
fruits.toDF().show()

Cela affichera les 20 premières lignes de vos données, donc la taille de vos données ne devrait pas être un problème.

+------+---+                                                                    
|    _1| _2|
+------+---+
| apple|  1|
|banana|  2|
|orange| 17|
+------+---+
Wesam
la source
1
Je pense que c'estimport spark.implicits._
Ryan Hartman
Quelle est la bibliothèque a été utilisée ici? Je ne peux pas détecter ni toDFni spark.implicits._dans l'étincelle.
Sergii le
1

Il existe probablement de nombreuses différences architecturales entre myRDD.foreach(println)et myRDD.collect().foreach(println)(non seulement «collecter», mais aussi d'autres actions). L'une des différences que j'ai constatées est que lors de l'exécution myRDD.foreach(println), la sortie sera dans un ordre aléatoire. Par exemple: si mon rdd provient d'un fichier texte où chaque ligne a un numéro, la sortie aura un ordre différent. Mais quand je l'ai fait myRDD.collect().foreach(println), l'ordre reste exactement comme le fichier texte.

Karan Gupta
la source
1

En python

   linesWithSessionIdCollect = linesWithSessionId.collect()
   linesWithSessionIdCollect

Cela imprimera tout le contenu du RDD

Niranjan Molkeri
la source
1
Merci mais j'ai tagué cette question avec scala not python
blue-sky
1
c.take(10)

et la version plus récente de Spark affichera bien la table.

Harvey
la source
1

Au lieu de taper à chaque fois, vous pouvez;

[1] Créez une méthode d'impression générique dans Spark Shell.

def p(rdd: org.apache.spark.rdd.RDD[_]) = rdd.foreach(println)

[2] Ou mieux encore, en utilisant des implicits, vous pouvez ajouter la fonction à la classe RDD pour imprimer son contenu.

implicit class Printer(rdd: org.apache.spark.rdd.RDD[_]) {
    def print = rdd.foreach(println)
}

Exemple d'utilisation:

val rdd = sc.parallelize(List(1,2,3,4)).map(_*2)

p(rdd) // 1
rdd.print // 2

Production:

2
6
4
8

Important

Cela n'a de sens que si vous travaillez en mode local et avec une petite quantité de données. Sinon, vous ne pourrez pas voir les résultats sur le client ou vous manquerez de mémoire en raison du résultat du grand ensemble de données.

noego
la source
0

Vous pouvez également enregistrer sous forme de fichier: rdd.saveAsTextFile("alicia.txt")

Thomas Decaux
la source
0

Dans la syntaxe java:

rdd.collect().forEach(line -> System.out.println(line));
ForeverLearner
la source