MapReduce编程规范:

(1)用户编写的程序分成三个部分:Mapper,Reducer,Driver(提交运行mr程序的客户端)

(2)Mapper的输入数据是KV对的形式(KV的类型可自定义)

(3)Mapper的输出数据是KV对的形式(KV的类型可自定义)

(4)Mapper中的业务逻辑写在map()方法中

(5)map()方法(maptask进程)对每一个<K,V>调用一次

(6)Reducer的输入数据类型对应Mapper的输出数据类型,也是KV

(7)Reducer的业务逻辑写在reduce()方法中

(8)Reducetask进程对每一组相同k的<k,v>组调用一次reduce()方法

(9)用户自定义的Mapper和Reducer都要继承各自的父类

(10)整个程序需要一个Drvier来进行提交,提交的是一个描述了各种必要信息的job对象

 

WordCount:在给定的文本文件中统计输出每一个单词出现的总次数

 



1 package com.ahu.bigdata.mr;
  2 
  3 import java.io.IOException;
  4 
  5 import org.apache.hadoop.conf.Configuration;
  6 import org.apache.hadoop.fs.Path;
  7 import org.apache.hadoop.io.IntWritable;
  8 import org.apache.hadoop.io.LongWritable;
  9 import org.apache.hadoop.io.Text;
 10 import org.apache.hadoop.mapreduce.Job;
 11 import org.apache.hadoop.mapreduce.Mapper;
 12 import org.apache.hadoop.mapreduce.Reducer;
 13 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
 14 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
 15 
 16 /**
 17  * 在给定的文本文件中统计出每一个单词出现的总次数
 18  * 
 19  * @author ahu_lichang
 20  * 
 21  */
 22 public class WordCountDriver {
 23     /**
 24      * 自定义mapper类
 25      * 
 26      * @author ahu_lichang
 27      * 
 28      */
 29     static class WordCountMapper extends
 30             Mapper<LongWritable, Text, Text, IntWritable> {
 31         // map方法的生命周期:框架每传一行数据就被调用一次
 32         // key:这一行的起始点在文件中的偏移量
 33         // value:这一行的内容
 34         @Override
 35         protected void map(LongWritable key, Text value, Context context)
 36                 throws IOException, InterruptedException {
 37             // 拿到一行数据转换为String
 38             String line = value.toString();
 39             // 将这一行切分出各个单词
 40             String[] words = line.split("\t");
 41             // 遍历数组,输出<单词,1>
 42             for (String word : words) {
 43                 context.write(new Text(word), new IntWritable(1));
 44             }
 45         }
 46     }
 47 
 48     /**
 49      * 自定义一个reducer类
 50      * 
 51      * @author ahu_lichang
 52      * 
 53      */
 54     static class WordCountReducer extends
 55             Reducer<Text, IntWritable, Text, IntWritable> {
 56         // reduce生命周期:框架每传递进来一个KV组,reduce方法就被调用一次
 57         @Override
 58         protected void reduce(Text key, Iterable<IntWritable> values,
 59                 Context context) throws IOException, InterruptedException {
 60             // 定义一个计数器
 61             int count = 0;
 62             // 遍历这一组KV的所有V,累加到count中
 63             for (IntWritable value : values) {
 64                 count += value.get();
 65             }
 66             context.write(key, new IntWritable(count));
 67         }
 68     }
 69 
 70     private static final String INPUT_PATH = "hdfs://hadoop1:9000/data.txt";
 71     private static final String OUT_PATH = "hdfs://hadoop1:9000/wcoutput";
 72 
 73     // WordCountDriver是一个主类,用来描述job并提交job
 74     // 相当于一个yarn集群的客户端
 75     // 需要在此封装我们的mr程序的相关运行参数,指定jar包
 76     // 最后提交给yarn
 77     public static void main(String[] args) throws Exception {
 78         if (args == null || args.length == 0) {
 79             args = new String[2];
 80             args[0] = INPUT_PATH;
 81             args[1] = OUT_PATH;
 82         }
 83         // 把业务逻辑相关的信息(哪个是mapper,哪个是reducer,要处理的数据在哪里,输出的结果放在哪里...)描述成一个job对象
 84         // 把这个描述好的job提交给集群去运行
 85         Configuration conf = new Configuration();
 86         Job job = Job.getInstance(conf);
 87 
 88         // 指定这个job所在的jar包
 89         // job.setJar("/usr/local/wordcount.jar");
 90         job.setJarByClass(WordCountDriver.class);
 91 
 92         job.setMapperClass(WordCountMapper.class);
 93         job.setReducerClass(WordCountReducer.class);
 94 
 95         // 设置业务逻辑Mapper类的输出key和value的数据类型
 96         job.setMapOutputKeyClass(Text.class);
 97         job.setMapOutputValueClass(IntWritable.class);
 98 
 99         // 设置业务逻辑Reducer类的输出key和value的数据类型
100         job.setOutputKeyClass(Text.class);
101         job.setOutputValueClass(IntWritable.class);
102 
103         // 指定job的输入原始文件所在目录
104         //FileInputFormat.setInputPaths(job, new Path(INPUT_PATH));
105         FileInputFormat.setInputPaths(job, new Path(args[0]));
106         // 指定job的输出结果所在目录
107         //FileOutputFormat.setOutputPath(job, new Path(OUT_PATH));
108         FileOutputFormat.setOutputPath(job, new Path(args[1]));
109 
110         // 将job中配置的相关参数,以及job所用的java类所在的jar包,提交给yarn集群去运行
111         /* job.submit(); */
112         boolean res = job.waitForCompletion(true);
113         System.exit(res ? 0 : 1);
114 
115     }
116 
117 }



 

 

 

1、先在eclipse工程中创建一个用户类库hadoop264jar,将hadoop安装目录中的share文件夹中的common、hdfs、MapReduce、yarn中的jar包全部添加进去。

2、书写代码:创建一个mapper自定义类,在创建一个reducer自定义类,最后创建一个描述job并提交job的主类。

3、运行方式有两种:

      (1)直接在eclipse中运行。但是会出现个权限拒绝错误,那是因为没有身份标识造成的。这里再介绍第二种身份标识方式:(第一种身份标识方式,见《HDFS详解》)

        

mapreduce讲解_开发工具

 

      (2)在集群上打包运行。先将书写好的代码打成jar包,然后将wordcount.jar复制到Linux的/usr/local/目录下,然后就可以在命令行中运行了。

        hadoop jar /usr/local/wordcount.jar /data.txt /wcout

         

mapreduce讲解_java_02

 

MapReduce程序运行模式:

1、本地运行模式

2、集群运行模式

 

MapReduce中的Combiner(归约)《Combiner》里面有代码示例

(1)combiner是MR程序中Mapper和Reducer之外的一种组件

(2)combiner组件的父类就是Reducer

(3)combiner和reducer的区别在于运行的位置:

是在每一个maptask所在的节点运行

是接收全局所有Mapper的输出结果;

(4) combiner的意义就是对每一个maptask的输出进行局部汇总,以减小网络传输量

具体实现步骤:

自定义一个combiner继承Reducer,重写reduce方法

在job中设置:  job.setCombinerClass(CustomCombiner.class)

(5) combiner能够应用的前提是不能影响最终的业务逻辑。而且,combiner的输出kv应该跟reducer的输入kv类型要对应起来

注意:

Combiner的使用要非常谨慎

因为combiner在mapreduce过程中可能调用也可能不调用,可能调一次也可能调多次

所以:combiner使用的原则是:有或没有都不能影响业务逻辑