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));
}
}
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.
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".
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