Zmiana nazw plików części w Hadoop Map Reduce

Próbowałem użyć klasy MultipleOutputs Jak na przykładzie na stronie http://hadoop.apache.org/docs/mapreduce/r0.21.0/api/index.html?org/apache/hadoop/mapreduce/lib/output/MultipleOutputs.html

Kod Kierowcy

    Configuration conf = new Configuration();
    Job job = new Job(conf, "Wordcount");
    job.setJarByClass(WordCount.class);
    job.setInputFormatClass(TextInputFormat.class);
    job.setMapperClass(WordCountMapper.class);
    job.setReducerClass(WordCountReducer.class);
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(IntWritable.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
    FileInputFormat.setInputPaths(job, new Path(args[0]));
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
    MultipleOutputs.addNamedOutput(job, "text", TextOutputFormat.class,
            Text.class, IntWritable.class);
    System.exit(job.waitForCompletion(true) ? 0 : 1);

Kod Reduktora

public class WordCountReducer extends
        Reducer<Text, IntWritable, Text, IntWritable> {
    private IntWritable result = new IntWritable();
    private MultipleOutputs<Text, IntWritable> mos;
    public void setup(Context context){
        mos = new MultipleOutputs<Text, IntWritable>(context);
    }
    public void reduce(Text key, Iterable<IntWritable> values, Context context)
            throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable val : values) {
            sum += val.get();
        }
        result.set(sum);
        //context.write(key, result);
        mos.write("text", key,result);
    }
    public void cleanup(Context context)  {
         try {
            mos.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         }
}

Wyjście reduktora zmienia nazwę na text-r-00000

Ale problem polega na tym, że dostaję również pusty plik part-r-00000. Czy w ten sposób powinno się zachowywać MultipleOutputs, czy jest jakieś problem z moim kodem? Proszę o radę.

Inną alternatywą, którą wypróbowałem, jest iteracja w moim folderze wyjściowym przy użyciu klasy systemu plików i Ręczna zmiana nazw wszystkich plików zaczynających się od części.

Jaki jest najlepszy sposób?

FileSystem hdfs = FileSystem.get(configuration);
FileStatus fs[] = hdfs.listStatus(new Path(outputPath));
for (FileStatus aFile : fs) {
if (aFile.isDir()) {
hdfs.delete(aFile.getPath(), true);
// delete all directories and sub-directories (if any) in the output directory
} 
else {
if (aFile.getPath().getName().contains("_"))
hdfs.delete(aFile.getPath(), true);
// delete all log files and the _SUCCESS file in the output directory
else {
hdfs.rename(aFile.getPath(), new Path(myCustomName));
}
}
Author: Balder, 2013-01-28

2 answers

Nawet jeśli używasz MultipleOutputs, domyślne OutputFormat (wierzę, że jest to TextOutputFormat) jest nadal używane, więc zainicjalizuje i utworzy te part-r-xxxxx pliki, które widzisz.

Fakt, że są puste, wynika z tego, że nie robisz żadnych context.write, ponieważ używasz MultipleOutputs. Ale to nie uniemożliwia ich tworzenia podczas inicjalizacji.

Aby się ich pozbyć, musisz zdefiniować swoją OutputFormat, aby powiedzieć, że nie oczekujesz żadnego wyjścia. Możesz to zrobić sposób:

job.setOutputFormat(NullOutputFormat.class);

Z tym zestawem właściwości, powinno to zapewnić, że pliki part nigdy nie zostaną zainicjowane, ale nadal otrzymujesz dane wyjściowe w MultipleOutputs.

Możesz również prawdopodobnie użyć LazyOutputFormat, co zapewni, że Twoje pliki wyjściowe są tworzone tylko wtedy, gdy / jeśli są jakieś dane, a nie inicjalizują puste pliki. Możesz zrobić tak:

import org.apache.hadoop.mapreduce.lib.output.LazyOutputFormat; 
LazyOutputFormat.setOutputFormatClass(job, TextOutputFormat.class);

Zauważ, że używasz w swoim Reducer prototyp MultipleOutputs.write(String namedOutput, K key, V value), który używa tylko domyślnej ścieżki wyjściowej, która zostanie wygenerowana na podstawie Twojego namedOutput do czegoś takiego: {namedOutput}-(m|r)-{part-number}. Jeśli chcesz mieć większą kontrolę nad wyjściowymi nazwami plików, powinieneś użyć prototypu MultipleOutputs.write(String namedOutput, K key, V value, String baseOutputPath), który może pozwolić ci uzyskać nazwy plików generowane w czasie wykonywania na podstawie Twoich kluczy / wartości.

 21
Author: Charles Menguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-28 04:46:25

To wszystko, co musisz zrobić w klasie Sterownika, aby zmienić nazwę bazową pliku wyjściowego: job.getConfiguration().set("mapreduce.output.basename", "text"); Spowoduje to, że Twoje pliki będą nazywane "text-r-00000".

 11
Author: RHolland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-03 12:08:55