MapReduce处理输出多文件格式(MultipleOutputs)

MultiPleOutputs原理

MapReduce job中,可以使用FileInputFormat和FileOutputFormat来对输入路径和输出路径来进行设置。在输出目录中,框架自己会自动对输出文件进行命名和组织,如part-(m|r)-00000之类,但有时为了后续流程的方便,我们常需要对输出结果进行一定的分类和组织。以前常用的方法是在MR job运行之后,用脚本对目录下的数据进行一次重新组织,变成我们需要的格式。

研究了一下MR框架中的MultipleOutputs(是2.0之后的新API,是对老版本中MultipleOutputs与MultipleOutputFormat的一个整合)。
在一般情况下,Hadoop每一个Reducer产生一个输出文件,文件以part-r-00000,part-r-00001的方式进行命名,如果需要认为的控制输出文件的命名或者每一个Reducer需要写出多个输出文件时,可以采用MultipleOutputs类来完成,MultipleOutputs采用输出记录的键值对(output Key和output Value)或者任意字符串来生成输出文件的名字,文件一般以name-r-nnnnn的格式进行命名,其中name是程序设计的任意名字;nnnnn表示分区号。

 

使用方法

1.驱动中不需要额外改变,只需要在MapClass或Reduce类中加入以下代码

[java]  view plain  copy
 print ?
  1. private MultipleOutputs<Text,IntWritable> mos;  
  2. public void setup(Context context) throws Exception{  
  3.   mos=new MultipleOutputs(context);  
  4. }  
  5. public void cleanup(Context context) throws Exeception{  
  6.   mos.close();  
  7. }   


2.然后就可以用mos.write(Key key,Value value,String baseOutputPath)代替context.write(key,value);
在MapClass或Reduce中使用,输出时也会有默认的文件part-m-00*或part-r-00*,不过这些文件是无内容的,大小为0。而且只有part-m-00*会传给reduce。

注意:
multipleOutputs.write(key,value,baseOutputPath)方法的第三个参数表明了该输出所在的目录(相当于用户指定的输出目录)。如果baseOutputPath不包含文件分隔符"/",那么输出的文件格式为baseOutputPath-r-nnnnn(name-r-nnnnn).
如果包含文件分隔符"/".例如baseOutputPath="029070-99999/1901/part",那么输出文件则为027070-99999/1901/part-r-nnnnn.

 

3.最后在job的类中

// 设置输出文件类型

[java]  view plain  copy
 print ?
  1. MultipleOutputs.addNamedOutput(job, namedOutput, outputFormatClass, keyClass, valueClass);  



 

 

 

案例

原始数据

1512,iphone5s,4inchs,A7,64,M7,lowerpower
1512,iphone5,4inchs,A6,IOS7
1512,iphone4s,3.5inchs,A5
50019780,Ipad,9.7,retina
50019780,yoga,lenovel,18hours
50019780,nexus,7,google
50019780,Ipad mini2,retina,7.9
1101,macbook air,OS X mavericks
1101,macbook pro,OS X lion
1101,thinkpad yoga,lenovel,windows 8

对原始数据根据第一个id列进行分类到不同的文件中

1.Map类

[java]  view plain  copy
 print ?
  1. package test.mr.multioutputs;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.hadoop.io.LongWritable;  
  6. import org.apache.hadoop.io.Text;  
  7. import org.apache.hadoop.mapreduce.Mapper;  
  8.   
  9. public class MultioutMap extends Mapper<LongWritable, Text, Text, Text> {  
  10.     @Override  
  11.     protected void map(LongWritable key, Text value,  
  12.             Mapper<LongWritable, Text, Text, Text>.Context context)  
  13.             throws IOException, InterruptedException {  
  14.         String line = value.toString().trim();  
  15.         if (line.length() > 0) {  
  16.             String str[] = line.split(",");  
  17.             // 提取分类  
  18.             context.write(new Text(str[0]), value);  
  19.         }  
  20.     }  
  21. }  


 

2.Reduce类

[java]  view plain  copy
 print ?
  1. package test.mr.multioutputs;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import org.apache.hadoop.io.NullWritable;  
  6. import org.apache.hadoop.io.Text;  
  7. import org.apache.hadoop.mapreduce.Reducer;  
  8. import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;  
  9.   
  10. public class MultioutRedu extends Reducer<Text, Text, NullWritable, Text> {  
  11.     private MultipleOutputs<NullWritable, Text> mos; // 输出类型和Reduce一致  
  12.   
  13.     @Override  
  14.     protected void setup(Reducer<Text, Text, NullWritable, Text>.Context context)  
  15.             throws IOException, InterruptedException {  
  16.         mos = new MultipleOutputs<NullWritable, Text>(context);  
  17.     }  
  18.   
  19.     @Override  
  20.     protected void cleanup(  
  21.             Reducer<Text, Text, NullWritable, Text>.Context context)  
  22.             throws IOException, InterruptedException {  
  23.         mos.close();  
  24.     }  
  25.   
  26.     @Override  
  27.     protected void reduce(Text key, Iterable<Text> values,  
  28.             Reducer<Text, Text, NullWritable, Text>.Context context)  
  29.             throws IOException, InterruptedException {  
  30.         /* 
  31.          * mos.write(Key key,Value 
  32.          * value,StringbaseOutputPath)代替context.write(key,value); 
  33.          */  
  34.         for (Text value : values) {  
  35.             // 指定写出不同文件的数据  
  36.             mos.write("KeySplit", NullWritable.get(), value, key.toString()  
  37.                     + "/");  
  38.             // 指定写出全部数据  
  39.             mos.write("AllData", NullWritable.get(), value);  
  40.         }  
  41.   
  42.     }  
  43. }  


 

3.job类

[java]  view plain  copy
 print ?
  1. package test.mr.multioutputs;  
  2.   
  3. import org.apache.hadoop.conf.Configuration;  
  4. import org.apache.hadoop.fs.Path;  
  5. import org.apache.hadoop.io.NullWritable;  
  6. import org.apache.hadoop.io.Text;  
  7. import org.apache.hadoop.mapreduce.Job;  
  8. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  9. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  10. import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;  
  11. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  12.   
  13. public class MultioutMain {  
  14.     public static void main(String[] args) throws Exception {  
  15.         Configuration conf = new Configuration();  
  16.         Job job = new Job(conf);  
  17.         job.setJarByClass(MultioutMain.class);  
  18.   
  19.         job.setMapperClass(MultioutMap.class);  
  20.         job.setMapOutputKeyClass(Text.class);  
  21.         job.setMapOutputValueClass(Text.class);  
  22.   
  23.         job.setReducerClass(MultioutRedu.class);  
  24.         job.setOutputKeyClass(NullWritable.class);  
  25.         job.setOutputValueClass(Text.class);  
  26.   
  27.         // 设置输出文件类型  
  28.         MultipleOutputs.addNamedOutput(job, "KeySplit", TextOutputFormat.class,  
  29.                 NullWritable.class, Text.class);  
  30.         MultipleOutputs.addNamedOutput(job, "AllData", TextOutputFormat.class,  
  31.                 NullWritable.class, Text.class);  
  32.           
  33.   
  34.         FileInputFormat.addInputPath(job, new Path(args[0]));  
  35.         FileOutputFormat.setOutputPath(job, new Path(args[1]));  
  36.         job.waitForCompletion(true);  
  37.     }  
  38. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值