MapReduce 程序模板 (采用 新/旧API)

来源:互联网 发布:程序算法高清壁纸 编辑:程序博客网 时间:2024/05/18 02:39
   最近在学习MapReduce编程,在仔细阅读了《Hadoop in Action》和《Hadoop: The Definitive Guide》两本书后,终于成功运行了一个自己写的MapReduce程序。 MapReduce程序一般都是在一个模板上进行修改拓展的,所以我这里将MapReduce模板贴出来。
            还有一个关键点: MapReduce的API在hadoop-0.20.0前后,发生了如下变化:

        (1)新的API倾向于使用抽象类,而不是接口。新的API中Mapper和Reducer是抽象类。

  (2)新的API在org.apache.hadoop.mapreduce包和子包中,旧版的API放在org.apache.hadoop.mapred中。在编程中一定要注意两个包不要混用或者用错,程序中要正确统一的的import进新包或者旧包。我在刚开始写代码的时候由于没有注意这一点,程序出现过错误,尤其是在刚建map或reduce类以及job的配置时。

  (3)新的API中广泛使用context object,例如MapContext基本上充当这JobConf的OutputCollector和Reporter的角色。

  (4)新的API同时支持“推”和“拉”式的迭代。

  (5)新的API同一了配置。旧API使用JobConf对象进行作业配置,新API中作业配置通过Configuration来完成。

  (6)新API中作业控制执行有Job类来负责,旧版使用JobClient。这也是写代码时要注意的地方。

         以上内容来自《Hadoop: The Definitive Guide》
  
         在代码中,我加上了一些自己认为重要的注意点,希望能有用。

旧API版的模板:

[java] view plaincopy
  1. import java.io.IOException;  
  2. import java.util.Iterator;  
  3.   
  4. import org.apache.hadoop.conf.Configuration;  
  5. import org.apache.hadoop.conf.Configured;  
  6. import org.apache.hadoop.fs.Path;  
  7. import org.apache.hadoop.io.Text;  
  8. import org.apache.hadoop.mapred.JobClient;  
  9. import org.apache.hadoop.mapred.Mapper;  
  10. import org.apache.hadoop.mapred.JobConf;  
  11. import org.apache.hadoop.mapred.MapReduceBase;  
  12. import org.apache.hadoop.mapred.OutputCollector;  
  13. import org.apache.hadoop.mapred.Reducer;  
  14. import org.apache.hadoop.mapred.Reporter;  
  15. import org.apache.hadoop.mapred.FileInputFormat;  
  16. import org.apache.hadoop.mapred.FileOutputFormat;  
  17. import org.apache.hadoop.mapred.KeyValueTextInputFormat;  
  18. import org.apache.hadoop.mapred.TextOutputFormat;  
  19.   
  20.   
  21. /** 
  22.  * 这里类的引用存在新旧版本的差异,在mapred里可以用JobConf,但是mapreduce里只有Job 
  23.  * 。而且FileInputOutFormat,FileOutputFormat是在两个类中都存在的,所以会导致下面 
  24.  * 的错误,只要将所有的都制定在一个类中,就可以了 
  25.  */  
  26. //import org.apache.hadoop.mapreduce.Job;  
  27. //import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  28. //import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;  
  29. //import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  30. //import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  31.   
  32. import org.apache.hadoop.util.Tool;  
  33. import org.apache.hadoop.util.ToolRunner;  
  34.   
  35. /** 
  36.  *  
  37.  * @author napoleongjc 
  38.  * @version 1.0 
  39.  */  
  40. /* 
  41.  * 是一个Map/Reduce框架提供的用于收集 Mapper或Reducer输出数据的通用机制 
  42.  * (包括中间输出结果和作业的输出结果)。 
  43.  * Reporter是用于Map/Reduce应用程序报告进度,设定应用级别的状态消息,  
  44.  * 更新Counters(计数器)的机制。 
  45.  */  
  46. public class MyJob extends Configured implements Tool{  
  47.     //記牢Map Reduce的类签名格式  
  48.     public static class MapClass extends MapReduceBase  
  49.         implements Mapper<Text, Text, Text, Text>{  
  50.         public void map(Text key, Text value,   
  51.         OutputCollector<Text, Text> output,   
  52.         Reporter reporter) throws IOException{  
  53.             output.collect(value, key); //输出键值对  
  54.         }  
  55.     }  
  56.       
  57.     public static class Reduce extends MapReduceBase  
  58.         implements Reducer<Text, Text, Text, Text>{//<K3,V3>一定要是Writable的子类,确保Hadoop的序列化接口可以吧数据在分布式集群上发                                                            //送,这里没有按照这个注意点  
  59.         public void reduce(Text key, Iterator<Text> values,  
  60.                 OutputCollector<Text, Text> output,  
  61.                 Reporter reporter) throws IOException{  
  62.             String csv = "";  
  63.             while (values.hasNext()){ //这里的迭代方式和前面的Iterator一致  
  64.                 if (csv.length() > 0)  
  65.                     csv += ",";  
  66.                 csv += values.next().toString();  
  67.             }  
  68.             output.collect(key, new Text(csv)); //输出前将count强制转化成IntWritable  
  69.         }  
  70.     }  
  71.       
  72.     /** 
  73.      * run被称为是框架的核心,也称为Driver,里面实例化,配置了一个JobConf对象,也就是说: 
  74.      * 在run里面,是整个任务的前提环境。 
  75.      */  
  76.     public int run(String[] args) throws Exception{  
  77.         Configuration conf = getConf();  
  78.           
  79. //      Job job = new Job(conf, "MyJob");  
  80. //      Path in = new Path(args[0]);  
  81. //      Path out = new Path(args[1]);  
  82. //      FileInputFormat.setInputPaths(job, in);  
  83. //      FileOutputFormat.setOutputPath(job, out);  
  84.           
  85.         /** 
  86.          * 关于上面这段代码,我觉得还有以下的写法,上面是都采用mapred类, 
  87.          * 下面就是采用mapreduce类 
  88.          */  
  89.         JobConf job = new JobConf(conf, MyJob.class);  
  90.           
  91.         Path in = new Path(args[0]);  
  92.         Path out = new Path(args[1]);  
  93.         FileInputFormat.setInputPaths(job, in);  
  94.         FileOutputFormat.setOutputPath(job, out);  
  95.           
  96.         job.setJobName("MyJob"); //设置文件的类型名  
  97.         job.setMapperClass(MapClass.class);//Map类是哪个  
  98.         job.setReducerClass(Reduce.class);//Reduce类是哪个  
  99.           
  100.         job.setInputFormat(KeyValueTextInputFormat.class); //设置Job的分割与读取文件的方式  
  101.         job.set("key.value.separator.in.input.line"","); //  设置在读取数据时,采用那种输出分割符  
  102.         job.setOutputFormat(TextOutputFormat.class);//设置Job输出数据到文件的格式,不是Reduce的输出,是整个Job的输出  
  103.         job.setOutputKeyClass(Text.class); //Map Reduce的输出Key格式,要是Map和Reduce中的类型不同,Map可以用setMapOutputKeyClass  
  104.         job.setOutputValueClass(Text.class);//MapReduce输出Value格式,要是Map和Reduce中的类型不同,Map可以用setMapOutputValueClass  
  105.           
  106.         JobClient.runJob(job); //运行作业  
  107.         return 0;  
  108.     }  
  109.   
  110.     public static void main(String[] args) throws Exception{  
  111.         int res = ToolRunner.run(new Configuration(), new MyJob(), args);  
  112.         System.exit(res);  
  113.     }  
  114. }  

新API模板:MyJobNew.java
[java] view plaincopy
  1. <strong><span style="font-size:12px;">  
  2. </span></strong>import java.io.IOException;  
  3.   
  4. import org.apache.hadoop.conf.Configuration;  
  5. import org.apache.hadoop.conf.Configured;  
  6. import org.apache.hadoop.fs.Path;  
  7. import org.apache.hadoop.io.LongWritable;  
  8. import org.apache.hadoop.io.Text;  
  9. import org.apache.hadoop.mapreduce.Job;  
  10. import org.apache.hadoop.mapreduce.Mapper;  
  11. import org.apache.hadoop.mapreduce.Reducer;  
  12. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  13. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  14. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  15. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  16. import org.apache.hadoop.util.Tool;  
  17. import org.apache.hadoop.util.ToolRunner;  
  18.   
  19. /** 
  20.  *  
  21.  * @author napoleongjc 
  22.  * @写这个模板是为了体现出两个版本之间的API之间的不同,他们的不同主要体现在MapReduce之间的差距 
  23.  */  
  24. public class MyJobNew extends Configured implements Tool{  
  25.       
  26.     /* 
  27.      * 首先,Map类和Reduce类的签名就不一样, 
  28.      * 1.直接继承自Mapper和Reducer类,不用集成MapReduceBase再Implements Mapper 
  29.      * 2.中间输出和Reduce输出采用Context上下文对象,不再是OutputCollector + Reporter 
  30.      * 3.输出键/值对,采用context对象的write()方法,不是原来的collector.collect() 
  31.      */  
  32.     public static class MapClass  
  33.         extends Mapper<LongWritable, Text, Text, Text>{ //直接继承自Mapper  
  34.         public void map(LongWritable key, Text value, Context context) //输出直接采用Context的对象  
  35.                     throws IOException, InterruptedException { //除了IOException,还有InterruptedException  
  36.             String[] citation = value.toString().split(",");  
  37.             context.write(new Text(citation[1]), new Text(citation[0]));//输出<K2,V2>键值对  
  38.         }  
  39.     }  
  40.   
  41.     /** 
  42.      * Combiner的作用就是将Mapper的结果先部分合并,减小Mapper和Reducer之间的 
  43.      * 网络流量,节省资源 
  44.      * 1.通过reducer的接口来定义,所以他基本上与reducer函数相同 
  45.      * 2.只需在run中设置的时候添加setCombinerClass(xxxx.class)就行了 
  46.      */  
  47.     public static class Combine   
  48.         extends Reducer<Text, Text, Text, Text>{  
  49.         public void reduce(Text key, Iterable<Text> values, Context context)//迭代方式是Iterable,不同与以前的Iterator  
  50.                     throws IOException, InterruptedException{  
  51.             String csv = "";  
  52.             for (Text val:values){ //所以迭代方式都是不一样的  
  53.                 if (csv.length() > 0)  
  54.                     csv += ",";  
  55.                 csv += val.toString();  
  56.             }  
  57.             context.write(key, new Text(csv)); //输出  
  58.           
  59.         }  
  60.     }  
  61.       
  62.     public static class Reduce   
  63.         extends Reducer<Text, Text, Text, Text>{  
  64.         public void reduce(Text key, Iterable<Text> values, Context context)//迭代方式是Iterable,不同与以前的Iterator  
  65.                     throws IOException, InterruptedException{  
  66.             String csv = "";  
  67.             for (Text val:values){ //所以迭代方式都是不一样的  
  68.                 if (csv.length() > 0)  
  69.                     csv += ",";  
  70.                 csv += val.toString();  
  71.             }  
  72.             context.write(key, new Text(csv)); //输出  
  73.               
  74.         }  
  75.     }  
  76.       
  77.     /* 
  78.      *Driver也不同。 
  79.      *1.Configuration和JobConf的功能被Configuration和Job替代,所以定义设置和作业的方式不同了 
  80.      *2.设置Job读取文件/输出文件的方法名变了 setInputFormat -> setInputFormatClass 
  81.      *3.提交作业,以前是JobClient.runJob(job),现在是 System.exit(job.waitForCompletion(true)?0:1) 
  82.      */  
  83.     public int run(String[] args) throws Exception{  
  84.         /* 
  85.          * Configuration是为了设置作业 
  86.          */  
  87.         Configuration conf = getConf();  
  88.            
  89.         /* 
  90.          * Job定义和控制一个作业 
  91.          */  
  92.         Job job = new Job(conf, "MyJobNew");  
  93.         job.setJarByClass(MyJobNew.class);  
  94.           
  95.         Path in = new Path(args[0]);  
  96.         Path out = new Path(args[1]);  
  97.         FileInputFormat.setInputPaths(job, in);  
  98.         FileOutputFormat.setOutputPath(job, out);  
  99.           
  100.         job.setMapperClass(MapClass.class);  
  101.         job.setCombinerClass(Combine.class);  
  102.         job.setReducerClass(Reduce.class);  
  103.           
  104.         job.setInputFormatClass(TextInputFormat.class);  
  105.         job.setOutputFormatClass(TextOutputFormat.class);  
  106.         job.setOutputKeyClass(Text.class);  
  107.         job.setOutputValueClass(Text.class);  
  108.           
  109.         System.exit(job.waitForCompletion(true)?0:1); //run the job  
  110.           
  111.         return 0;  
  112.     }  
  113.       
  114.     public static void main(String[] args) throws Exception{  
  115.         int res = ToolRunner.run(new Configuration(), new MyJobNew(), args);  
  116.           
  117.         System.exit(res);  
  118.     }  
  119. }  
0 0