Hadoop的MapReduce中多文件輸出

My_LineRead.java

[java] view plaincopy
  1. public class My_LineRead<K, V> extends RecordWriter<K, V>{  
  2.         private static final String utf8 = "UTF-8";  
  3.         private static final  String colon = "----";  //劃分符號  
  4.         private static final byte[] newline;  
  5.         static {  
  6.           try {  
  7.             newline = "/n".getBytes(utf8);  
  8.           } catch (UnsupportedEncodingException uee) {  
  9.             throw new IllegalArgumentException("can't find " + utf8 + " encoding");  
  10.           }  
  11.         }  
  12.         protected DataOutputStream out;  
  13.         private final byte[] keyValueSeparator;  
  14.           
  15.         public My_LineRead(DataOutputStream out) {  
  16.             this(out, colon); //調用下面的構造函數  
  17.         }  
  18.         public My_LineRead(DataOutputStream out, String keyValueSeparator) {  
  19.             // TODO Auto-generated constructor stub  
  20.             this.out = out;  
  21.             try {  
  22.                 this.keyValueSeparator = keyValueSeparator.getBytes(utf8);  
  23.             } catch (UnsupportedEncodingException e) {  
  24.                 // TODO Auto-generated catch block  
  25.                 throw new IllegalArgumentException("can't find " + utf8 + " encoding");  
  26.             }  
  27.         }  
  28.         @Override  
  29.         public void close(TaskAttemptContext arg0) throws IOException,  
  30.                 InterruptedException {  
  31.             // TODO Auto-generated method stub  
  32.             out.close();  
  33.         }  
  34.   
  35.         @Override  
  36.         public void write(K key, V value) throws IOException,  
  37.                 InterruptedException {  
  38.             if (!(key == null && key instanceof NullWritable)){  
  39.                 //如果key不爲空者輸出key  
  40.                 if ((Object)key instanceof Text){  
  41.                     Text to = (Text) key;  
  42.                     out.write(to.getBytes(), 0, to.getLength());  
  43.                 }  
  44.                 else  
  45.                 {  
  46.                     out.write(key.toString().getBytes(utf8));  
  47.                 }  
  48.                 out.write(keyValueSeparator);  
  49.             }  
  50.             if (!(value == null && value instanceof NullWritable)){  
  51.                 //如果value不爲空則輸出value  
  52.                 if ((Object)value instanceof Text){  
  53.                     Text to = (Text) value;  
  54.                     out.write(to.getBytes(), 0, to.getLength());  
  55.                 }  
  56.                 else  
  57.                 {  
  58.                     out.write(value.toString().getBytes(utf8));  
  59.                 }  
  60.                 out.write(newline);  
  61.             }  
  62.               
  63.         }  
  64.     }  

MyMultipleOutputFormat.java //這個類,我添加了些註釋便於理解

[c-sharp] view plaincopy
  1. public abstract class MyMultipleOutputFormat  <K extends WritableComparable<?>, V extends Writable>    
  2.         extends FileOutputFormat<K, V> {  
  3.     //接口類,需要在主程序中實現generateFileNameForKeyValue來獲取文件名  
  4.     private MultiRecordWriter writer = null;    
  5.     @Override  
  6.     public RecordWriter<K, V> getRecordWriter(TaskAttemptContext job)  
  7.             throws IOException, InterruptedException {  
  8.         // TODO Auto-generated method stub  
  9.         //如果第一次調用那麼writer=null  
  10.         if (writer == null) {    
  11.             //getTaskOutputPath獲取output路徑  
  12.             writer = new MultiRecordWriter(job, getTaskOutputPath(job));    
  13.         }    
  14.         return writer;  
  15.     }  
  16.     private Path getTaskOutputPath(TaskAttemptContext conf) throws IOException {  
  17.         Path workPath = null;  
  18.         OutputCommitter committer = super.getOutputCommitter(conf);  
  19.         if (committer instanceof FileOutputCommitter) {  
  20.             workPath = ((FileOutputCommitter) committer).getWorkPath();  
  21.         } else {  
  22.             Path outputPath = super.getOutputPath(conf);  
  23.             if (outputPath == null) {  
  24.                 throw new IOException("Undefined job output-path");  
  25.             }  
  26.             workPath = outputPath;  
  27.         }  
  28.         return workPath;  
  29.     }  
  30.     /**通過key, value, conf來確定輸出文件名(含擴展名)*/  
  31.     //返回值就是文件名。可以根據key,value來判斷  
  32.     protected abstract String generateFileNameForKeyValue(K key, V value, Configuration conf);  
  33.       
  34.     //MultiRecordWriter類  
  35.     public class MultiRecordWriter extends RecordWriter<K, V> {  
  36.         /**RecordWriter的緩存*/  
  37.         private HashMap<String, RecordWriter<K, V>> recordWriters = null;  
  38.         private TaskAttemptContext job = null;  
  39.         /**輸出目錄*/  
  40.         private Path workPath = null;  
  41.         //構造函數  
  42.         public MultiRecordWriter(TaskAttemptContext job, Path workPath) {  
  43.             super();  
  44.             this.job = job;  
  45.             this.workPath = workPath;  
  46.             recordWriters = new HashMap<String, RecordWriter<K, V>>();  
  47.         }  
  48.         //關閉,應該可能是多個文件進行關閉,所有采用循環  
  49.         //recordWriters.values() 就是指的getBaseRecordWriter返回的值。  
  50.         @Override  
  51.         public void close(TaskAttemptContext context) throws IOException, InterruptedException {  
  52.             Iterator<RecordWriter<K, V>> values = this.recordWriters.values().iterator();  
  53.             while (values.hasNext()) {  
  54.                 values.next().close(context);  
  55.             }  
  56.             this.recordWriters.clear();  
  57.         }  
  58.         @Override  
  59.         public void write(K key, V value) throws IOException, InterruptedException {  
  60.             //得到輸出文件名  
  61.             String baseName = generateFileNameForKeyValue(key, value, job.getConfiguration());  
  62.             //如果recordWriters裏沒有文件名,那麼就建立。否則就直接寫值。  
  63.             RecordWriter<K, V> rw = this.recordWriters.get(baseName);  
  64.             if (rw == null) {  
  65.                 rw = getBaseRecordWriter(job, baseName);  
  66.                 //放入HashMap  
  67.                 this.recordWriters.put(baseName, rw);  
  68.             }  
  69.             rw.write(key, value);  
  70.         }  
  71.         // ${mapred.out.dir}/_temporary/_${taskid}/${nameWithExtension}  
  72.         private RecordWriter<K, V> getBaseRecordWriter(TaskAttemptContext job, String baseName)  
  73.                 throws IOException, InterruptedException {  
  74.             //獲取配置文件  
  75.             Configuration conf = job.getConfiguration();  
  76.             //查看是否使用解碼器  
  77.             boolean isCompressed = getCompressOutput(job);  
  78.             String keyValueSeparator = ",";  
  79.             RecordWriter<K, V> recordWriter = null;  
  80.             if (isCompressed) {  
  81.                 Class<? extends CompressionCodec> codecClass = getOutputCompressorClass(job,  
  82.                         GzipCodec.class);  
  83.                 CompressionCodec codec = ReflectionUtils.newInstance(codecClass, conf);  
  84.                 Path file = new Path(workPath, baseName + codec.getDefaultExtension());  
  85.                 FSDataOutputStream fileOut = file.getFileSystem(conf).create(file, false);  
  86.                 recordWriter = new My_LineRead<K, V>(new DataOutputStream(codec  
  87.                         .createOutputStream(fileOut)), keyValueSeparator);  
  88.             }  
  89.             //如果不使用解碼器  
  90.             else {  
  91.                 Path file = new Path(workPath, baseName);  
  92.                 FSDataOutputStream fileOut = file.getFileSystem(conf).create(file, false);  
  93.                 //recordWriter = new My_LineRead<K, V>(fileOut, keyValueSeparator);  
  94.                 //這裏我使用的我自己的OutputFormat  
  95.                 recordWriter = new My_LineRead<K, V>(fileOut);  
  96.             }  
  97.             return recordWriter;  
  98.         }  
  99.     }  
  100. }  

最後就是測試類,WordCount_MulFileOut.java

[java] view plaincopy
  1. public class WordCount_MulFileOut {  
  2.     public static  class wordcountMapper extends  
  3.         Mapper<LongWritable, Text, Text, IntWritable>{  
  4.         private final static IntWritable one = new IntWritable(1);  
  5.         private Text word = new Text();  
  6.         public void map(LongWritable key, Text value, Context context)throws IOException, InterruptedException{  
  7.             String line = value.toString();  
  8.             StringTokenizer itr = new StringTokenizer(line);  
  9.             while(itr.hasMoreElements()){  
  10.                 word.set(itr.nextToken());  
  11.                 context.write(word, one);  
  12.             }  
  13.         }  
  14.     }  
  15.     public static  class wordcountReduce extends  
  16.         Reducer<Text, IntWritable, Text, IntWritable>{  
  17.         public void reduce(Text key, Iterable<IntWritable>values, Context context)throws IOException, InterruptedException{  
  18.             int sum = 0;  
  19.             for (IntWritable str : values){  
  20.                 sum += str.get();  
  21.             }  
  22.             context.write(key, new IntWritable(sum));  
  23.         }  
  24.     }  
  25.     public static class MyMultiple extends MyMultipleOutputFormat{  
  26.   
  27.         @Override  
  28.         protected String generateFileNameForKeyValue(WritableComparable key,  
  29.                 Writable value, Configuration conf) {  
  30.             // TODO Auto-generated method stub  
  31.             return "other.txt";  
  32.         }  
  33.           
  34.     }  
  35.     public static  void main(String args[])throws Exception{  
  36.           
  37.         Configuration conf = new Configuration();  
  38.   
  39.         Job job = new Job(conf, "wordcount");  
  40.           
  41.         job.setJarByClass(WordCount_MulFileOut.class);  
  42.           
  43.         job.setInputFormatClass(TextInputFormat.class);  
  44.           
  45.         job.setOutputFormatClass(MyMultiple.class);  
  46.         job.setOutputKeyClass(Text.class);  
  47.         job.setOutputValueClass(IntWritable.class);  
  48.           
  49.         job.setMapperClass(wordcountMapper.class);  
  50.         job.setReducerClass(wordcountReduce.class);  
  51.         job.setCombinerClass(wordcountReduce.class);  
  52.           
  53.         FileInputFormat.setInputPaths(job, new Path(args[1]));  
  54.         FileOutputFormat.setOutputPath(job, new Path(args[2]));  
  55.           
  56.         job.waitForCompletion(true);  
  57.     }  
  58. }  


發佈了27 篇原創文章 · 獲贊 12 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章