J'ai une application de streaming spark qui produit un jeu de données pour chaque minute. J'ai besoin de sauvegarder/écraser les résultats des données traitées.
Lorsque j'ai essayé d'écraser l'ensemble de données org.Apache.hadoop.mapred.FileAlreadyExistsException, il arrête l'exécution.
J'ai défini la propriété Spark _ set("spark.files.overwrite","true")
, mais il n'y a pas de chance.
Comment écraser ou pré-supprimer les fichiers de spark?
UPDATE: Suggérez d'utiliser Dataframes
, plus quelque chose comme ... .write.mode(SaveMode.Overwrite) ...
.
Pour les anciennes versions, essayez
yourSparkConf.set("spark.hadoop.validateOutputSpecs", "false")
val sc = SparkContext(yourSparkConf)
Dans la version 1.1.0, vous pouvez définir les paramètres de configuration à l'aide du script spark-submit avec l'indicateur --conf.
AVERTISSEMENT (anciennes versions): Selon @piggybox, il existe un bogue dans Spark qui écrase uniquement les fichiers dont il a besoin pour écrire ses fichiers part-
. Tous les autres fichiers ne seront pas supprimés.
La documentation relative au paramètre spark.files.overwrite
indique ce qui suit: "Si les fichiers ajoutés via SparkContext.addFile()
doivent être écrasés lorsque le fichier cible existe et que son contenu ne correspond pas à celui de la source." Elle n’a donc aucun effet sur la méthode saveAsTextFiles.
Vous pouvez le faire avant d’enregistrer le fichier:
val hadoopConf = new org.Apache.hadoop.conf.Configuration()
val hdfs = org.Apache.hadoop.fs.FileSystem.get(new Java.net.URI("hdfs://localhost:9000"), hadoopConf)
try { hdfs.delete(new org.Apache.hadoop.fs.Path(filepath), true) } catch { case _ : Throwable => { } }
Aas a expliqué ici: http://Apache-spark-user-list.1001560.n3.nabble.com/How-can-I-make-Spark-1-0-saveAsTextFile-to-overwrite-existing- fichier-td6696.html
depuis df.save(path, source, mode)
est obsolète, ( http://spark.Apache.org/docs/1.5.0/api/scala/index.html#org.Apache.spark.sql.DataFrame )
utiliser df.write.format(source).mode("overwrite").save(path)
où df.write est DataFrameWriter
'source' peut être ("com.databricks.spark.avro" | "parquet" | "json")
Dans la documentation pyspark.sql.DataFrame.save (actuellement à la version 1.3.1), vous pouvez spécifier mode='overwrite'
lors de l’enregistrement d’un DataFrame:
myDataFrame.save(path='myPath', source='parquet', mode='overwrite')
J'ai vérifié que cela supprimera même les fichiers de partition laissés. Donc, si vous aviez dit 10 partitions/fichiers à l'origine, mais que vous avez ensuite écrasé le dossier avec un DataFrame qui n'avait que 6 partitions, le dossier résultant contiendrait les 6 partitions/fichiers.
Reportez-vous à documentation Spark SQL pour plus d'informations sur les options de mode.
df.write.mode ('écraser'). parquet ("/ output/folder/path") fonctionne si vous voulez écraser un fichier parquet en utilisant python. C'est dans spark 1.6.2. L'API peut être différent dans les versions ultérieures
val jobName = "WordCount";
//overwrite the output directory in spark set("spark.hadoop.validateOutputSpecs", "false")
val conf = new
SparkConf().setAppName(jobName).set("spark.hadoop.validateOutputSpecs", "false");
val sc = new SparkContext(conf)
Cette version surchargée de la fonction save fonctionne pour moi:
yourDF.save (outputPath, org.Apache.spark.sql.SaveMode.valueOf ("Ecraser"))
L'exemple ci-dessus écraserait un dossier existant. Le savemode peut également prendre ces paramètres ( https://spark.Apache.org/docs/1.4.0/api/Java/org/Apache/spark/sql/SaveMode.html ):
Append : le mode Append signifie que lors de l'enregistrement d'un DataFrame dans une source de données, si data/table existe déjà, le contenu du DataFrame devrait être ajouté à données existantes.
ErrorIfExists : le mode ErrorIfExists signifie que lors de l'enregistrement d'un DataFrame dans une source de données, si des données existent déjà, une exception doit être levée.
Ignore : le mode Ignore signifie que lors de la sauvegarde d'un DataFrame dans une source de données, si des données existent déjà, l'opération de sauvegarde ne devrait pas sauvegarder le contenu du fichier. DataFrame et ne pas modifier les données existantes.
Si vous souhaitez utiliser votre propre format de sortie personnalisé, vous pourrez également obtenir le comportement souhaité avec RDD.
Examinez les classes suivantes: FileOutputFormat , FileOutputCommitter
Dans le format de sortie du fichier, vous avez une méthode appelée checkOutputSpecs, qui vérifie si le répertoire de sortie existe. FileOutputCommitter contient le commitJob, qui transfère généralement les données du répertoire temporaire à son emplacement final.
Je ne pouvais pas encore le vérifier (le ferais dès que j'ai quelques minutes gratuites) mais théoriquement: Si j'étends FileOutputFormat et que je substitue checkOutputSpecs à une méthode qui ne lève pas d'exception sur le répertoire, ajuste le La méthode commitJob de mon créateur de sortie personnalisé exécute la logique que je souhaite (par exemple, remplacer certains des fichiers, en ajouter d’autres) que je ne serais peut-être en mesure d’obtenir le comportement souhaité avec les RDD.
Le format de sortie est transmis à: saveAsNewAPIHadoopFile (qui est la méthode saveAsTextFile également appelée pour enregistrer les fichiers). Et le déclencheur de sortie est configuré au niveau de l'application.