2011-04-12 13 views
8

Esta puede ser una pregunta básica, pero no pude encontrar una respuesta para ella en Google.
Tengo un trabajo map-reduce que crea múltiples archivos de salida en su directorio de salida. Mi aplicación Java ejecuta este trabajo en un clúster remoto de hadoop y, una vez finalizado el trabajo, debe leerse la salida de forma programática utilizando la API org.apache.hadoop.fs.FileSystem. ¿Es posible?
La aplicación conoce el directorio de salida, pero no los nombres de los archivos de salida generados por el trabajo map-reduce. Parece que no hay forma de enumerar programáticamente los contenidos de un directorio en la API del sistema de archivos hadoop. ¿Cómo se leerán los archivos de salida?
Parece un escenario tan común, que estoy seguro de que tiene una solución. Pero me falta algo muy obvio.Lectura programática del resultado del programa Mapreduce de Hadoop

Respuesta

19

El método que está buscando se llama listStatus (Path). Simplemente devuelve todos los archivos dentro de una ruta como una matriz FileStatus. Luego puede simplemente recorrerlos creando un objeto de ruta y leerlo.

FileStatus[] fss = fs.listStatus(new Path("/")); 
    for (FileStatus status : fss) { 
     Path path = status.getPath(); 
     SequenceFile.Reader reader = new SequenceFile.Reader(fs, path, conf); 
     IntWritable key = new IntWritable(); 
     IntWritable value = new IntWritable(); 
     while (reader.next(key, value)) { 
      System.out.println(key.get() + " | " + value.get()); 
     } 
     reader.close(); 
    } 

Para Hadoop 2.x se puede configurar el lector de la siguiente manera:

SequenceFile.Reader reader = 
      new SequenceFile.Reader(conf, SequenceFile.Reader.file(path)) 
+0

muchas gracias por su ayuda. – nabeelmukhtar

+1

@Thomas, listStatus también parece devolver otros archivos, p. Ej. _SUCCESS –

+0

Sí, pero ese no es mi problema;) Tienes que filtrar por ti mismo –

0

Usted tiene algunas opciones: aquí hay dos que a veces uso.

Método # 1: Dependiendo del tamaño de los datos, es hacer uso de los siguientes comandos de HDFS (encontrados here, artículo 6)

hadoop fs -getmerge hdfs-output-dir local-file 
// example 
hadoop fs -getmerge /user/kenny/mrjob/ /tmp/mrjob_output 
// another way 
hadoop fs -cat /user/kenny/mrjob/part-r-* > /tmp/mrjob_output 

"Este concatena el HDFS archivos hdfs-output- dir/part- * en un solo archivo local. "

Luego puede leer en un solo archivo. (Tenga en cuenta que está en el almacenamiento local y no HDFS)

Método # 2: Crear un método de ayuda: (tengo una clase llamada HDFS que contiene la configuración, las instancias de sistema de archivos como así como otros métodos de ayuda)

public List<Path> matchFiles(String path, final String filter) { 
     List<Path> matches = new LinkedList<Path>(); 
     try { 
      FileStatus[] statuses = fileSystem.listStatus(new Path(path), new PathFilter() { 
         public boolean accept(Path path) { 
          return path.toString().contains(filter); 
         } 
        }); 
      for(FileStatus status : statuses) { 
       matches.add(status.getPath()); 
      } 
     } catch(IOException e) { 
     LOGGER.error(e.getMessage(), e); 
     } 
     return matches; 
    } 

a continuación, puede llamar a través de un comando como este: hdfs.matchFiles("/user/kenny/mrjob/", "part-")

0
  FSDataInputStream inputStream = fs.open(path); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); 
      String record; 
      while((record = reader.readLine()) != null) { 
       int blankPos = record.indexOf(" "); 
       System.out.println(record+"blankPos"+blankPos); 
       String keyString = record.substring(0, blankPos); 
       String valueString = record.substring(blankPos + 1); 
       System.out.println(keyString + " | " + valueString); 
      } 
Cuestiones relacionadas