Программно считывает вывод программы Hadoop Mapreduce - PullRequest
8 голосов
/ 12 апреля 2011

Это может быть основной вопрос, но я не смог найти ответ на него в Google.
У меня есть задание уменьшения карты, которое создает несколько выходных файлов в своем выходном каталоге. Мое Java-приложение выполняет это задание на удаленном кластере Hadoop, и после того, как задание будет завершено, оно должно программно читать выходные данные, используя org.apache.hadoop.fs.FileSystem API. Возможно ли это?
Приложение знает выходной каталог, но не имена выходных файлов, сгенерированных заданием карты-сокращения. Кажется, нет никакого способа программно перечислить содержимое каталога в API файловой системы hadoop. Как будут читаться выходные файлы?
Кажется, это такой банальный сценарий, что я уверен, что у него есть решение. Но я упускаю что-то очень очевидное.

Ответы [ 3 ]

19 голосов
/ 12 апреля 2011

Метод, который вы ищете, называется listStatus (Path). Он просто возвращает все файлы внутри Path в виде массива FileStatus. Затем вы можете просто зациклить их, создать объект пути и прочитать его.

    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();
    }

Для Hadoop 2.x вы можете настроить читатель так:

 SequenceFile.Reader reader = 
           new SequenceFile.Reader(conf, SequenceFile.Reader.file(path))
0 голосов
/ 14 января 2016
            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);
            }
0 голосов
/ 17 июня 2013

У вас есть несколько вариантов: вот два, которые я иногда использую.

Метод # 1: В зависимости от размера ваших данных, использовать следующие команды HDFS (найдено здесь , пункт 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

"Это объединяет файлы HDFS hdfs-output-dir / part- * в один локальный файл."

Затем вы можете просто прочитать один файл.(обратите внимание, что он находится в локальном хранилище, а не в HDFS)

Метод # 2 : создайте вспомогательный метод: (У меня есть класс с именем HDFS, который содержит экземпляры Configuration, FileSystem, а такжедругие вспомогательные методы)

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;
    }

Затем вы можете вызвать такую ​​команду: hdfs.matchFiles("/user/kenny/mrjob/", "part-")

...