web-dev-qa-db-fra.com

Comment écrire dans CSV en Spark

J'essaie de trouver un moyen efficace d'enregistrer le résultat de mon Spark Job en tant que fichier csv. J'utilise Spark avec Hadoop et jusqu'à présent) tous mes fichiers sont enregistrés sous part-00000.

Des idées sur la façon de faire mon spark enregistrement dans un fichier avec un nom de fichier spécifié?

33
Karusmeister

Étant donné que Spark utilise l'API Hadoop File System pour écrire des données dans des fichiers, cela est inévitable. Si vous le faites

rdd.saveAsTextFile("foo")

Il sera enregistré sous "foo/part-XXXXX" Avec un fichier part- * chaque partition du RDD que vous essayez d'enregistrer. La raison pour laquelle chaque partition du RDD est écrite dans un fichier distinct est pour la tolérance aux pannes. Si la tâche d'écriture de la 3e partition (c'est-à-dire vers part-00002) Échoue, Spark simplement réexécutez la tâche et écrasez le part-00002 Partiellement écrit/corrompu, sans Si elles ont toutes écrit dans le même fichier, il est beaucoup plus difficile de récupérer une seule tâche en cas d'échec.

Les fichiers part-XXXXX Ne sont généralement pas un problème si vous allez les consommer à nouveau dans Spark/frameworks basés sur Hadoop parce qu'ils utilisent tous l'API HDFS, si vous leur demandez lire "foo", ils liront également tous les fichiers part-XXXXX dans foo.

52
Tathagata Das

Je vous suggère de le faire de cette façon (exemple Java):

theRddToPrint.coalesce(1, true).saveAsTextFile(textFileName);
FileSystem fs = anyUtilClass.getHadoopFileSystem(rootFolder);
FileUtil.copyMerge(
    fs, new Path(textFileName),
    fs, new Path(textFileNameDestiny),
    true, fs.getConf(), null);
10
adoalonso

Il existe une approche autre basée sur les opérations Hadoop FileSystem.

3
pls

J'ai une idée, mais pas d'extrait de code prêt. En interne (comme son nom l'indique) Spark utilise le format de sortie Hadoop. (Ainsi que InputFormat lors de la lecture depuis HDFS).

Dans le FileOutputFormat du hadoop, il y a un membre protégé setOutputFormat, que vous pouvez appeler à partir de la classe héritée pour définir un autre nom de base.

1
David Gruzman

Extension Tathagata Das réponse à Spark 2.x et Scala 2.11

En utilisant Spark SQL, nous pouvons le faire dans une seule ligne

//implicits for magic functions like .toDf
import spark.implicits._

val df = Seq(
  ("first", 2.0),
  ("choose", 7.0),
  ("test", 1.5)
).toDF("name", "vals")

//write DataFrame/DataSet to external storage
df.write
  .format("csv")
  .save("csv/file/location")

Ensuite, vous pouvez aller de l'avant et continuer avec la réponse de adoalonso .

1
mrsrinivas

Ce n'est pas vraiment une solution propre, mais dans un foreachRDD (), vous pouvez essentiellement faire ce que vous voulez, également créer un nouveau fichier.

Dans ma solution, voici ce que je fais: j'enregistre la sortie sur HDFS (pour des raisons de tolérance aux pannes), et à l'intérieur d'un foreachRDD je crée également un fichier TSV avec des statistiques dans un dossier local.

Je pense que vous pourriez probablement faire de même si c'est ce dont vous avez besoin.

http://spark.Apache.org/docs/0.9.1/streaming-programming-guide.html#output-operations

0
gprivitera