web-dev-qa-db-fra.com

Puis-je écrire un fichier HDFS (ou local) en texte brut à partir d'un programme Spark et non d'un RDD?

J'ai un programme Spark (en Scala) et un SparkContext. J'écris des fichiers avec RDD 's saveAsTextFile. Sur mon ordinateur local, je peux utiliser un chemin de fichier local et cela fonctionne avec le système de fichiers local. Sur mon cluster, cela fonctionne avec HDFS.

Je souhaite également écrire d'autres fichiers arbitraires à la suite d'un traitement. Je les écris sous forme de fichiers normaux sur mon ordinateur local, mais je souhaite les insérer dans HDFS sur le cluster.

SparkContext semble avoir quelques méthodes liées aux fichiers, mais elles semblent toutes être des entrées et non des sorties.

Comment puis-je faire cela?

8
Joe

Merci à marios et à kostya, mais l’écriture d’un fichier texte dans HDFS à partir de Spark ne nécessite que quelques étapes.

// Hadoop Config is accessible from SparkContext
val fs = FileSystem.get(sparkContext.hadoopConfiguration); 

// Output file can be created from file system.
val output = fs.create(new Path(filename));

// But BufferedOutputStream must be used to output an actual text file.
val os = BufferedOutputStream(output)

os.write("Hello World".getBytes("UTF-8"))

os.close()

Notez que FSDataOutputStream, qui a été suggéré, est un flux de sortie d'objet sérialisé Java, et non un flux de sortie de texte. La méthode writeUTF semble écrire du texte de requête, mais il s’agit en fait d’un format de sérialisation binaire qui inclut des octets supplémentaires.

9
Joe

Voici ce qui a fonctionné le mieux pour moi (avec Spark 2.0):

val path = new Path("hdfs://namenode:8020/some/folder/myfile.txt")
val conf = new Configuration(spark.sparkContext.hadoopConfiguration)
conf.setInt("dfs.blocksize", 16 * 1024 * 1024) // 16MB HDFS Block Size
val fs = path.getFileSystem(conf)
if (fs.exists(path))
    fs.delete(path, true)
val out = new BufferedOutputStream(fs.create(path)))
val txt = "Some text to output"
out.write(txt.getBytes("UTF-8"))
out.flush()
out.close()
fs.close()
4
Martin Tapp

À l'aide de l'API HDFS (hadoop-hdfs.jar), vous pouvez créer InputStream/OutputStream pour un chemin HDFS et lire/écrire dans un fichier à l'aide de classes Java.io standard. Par exemple:

URI uri = URI.create (“hdfs://Host:port/file path”);
Configuration conf = new Configuration();
FileSystem file = FileSystem.get(uri, conf);
FSDataInputStream in = file.open(new Path(uri));

Ce code fonctionnera également avec les fichiers locaux (changez hdfs:// en file://).

2
kostya

Un moyen simple d'écrire des fichiers sur HDFS consiste à utiliser un SequenceFiles . Ici, vous utilisez les API natives Hadoop et not celles fournies par Spark. 

Voici un extrait simple (en Scala):

import org.Apache.hadoop.conf.Configuration
import org.Apache.hadoop.fs._
import org.Apache.hadoop.io._ 

val conf = new Configuration() // Hadoop configuration 
val sfwriter = SequenceFile.createWriter(conf,
              SequenceFile.Writer.file(new Path("hdfs://nn1.example.com/file1")),
              SequenceFile.Writer.keyClass(LongWritable.class),
              SequenceFile.Writer.valueClass(Text.class))
val lw = new LongWritable()
val txt = new Text()
lw.set(12)
text.set("hello")
sfwriter.append(lw, txt)
sfwriter.close()
...

Si vous n'avez pas de clé, vous pouvez utiliser NullWritable.class à sa place:

SequenceFile.Writer.keyClass(NullWritable.class)
sfwriter.append(NullWritable.get(), new Text("12345"));
2
marios