Hadoop基础-MapReduce入门篇之编写简单的Wordcount测试代码
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
本文主要是记录一写我在学习MapReduce时的一些琐碎的学习笔记, 方便自己以后查看。在调用API的时候,可能会需要maven依赖,添加依赖的包如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <parent> 6 <artifactId>HADOOP</artifactId> 7 <groupId>yinzhengjie.org.cn</groupId> 8 <version>1.0-SNAPSHOT</version> 9 </parent> 10 <modelVersion>4.0.0</modelVersion> 11 12 <artifactId>MapReduce</artifactId> 13 14 <dependencies> 15 <dependency> 16 <groupId>org.apache.hadoop</groupId> 17 <artifactId>hadoop-common</artifactId> 18 <version>2.6.0</version> 19 </dependency> 20 21 <dependency> 22 <groupId>org.apache.hadoop</groupId> 23 <artifactId>hadoop-client</artifactId> 24 <version>2.6.0</version> 25 </dependency> 26 27 <dependency> 28 <groupId>junit</groupId> 29 <artifactId>junit</artifactId> 30 <version>4.11</version> 31 <scope>test</scope> 32 </dependency> 33 34 </dependencies> 35 36 37 </project>
一.MapReduce定义
Mapreduce是一个分布式运算程序的编程框架,是用户开发“基于hadoop的数据分析应用”的核心框架。
Mapreduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个hadoop集群上。
二.MapReduce优点
1>.MapReduce 易于编程。
它简单的实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行。也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点使得MapReduce编程变得非常流行。
2>.良好的扩展性。
当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。
3>.高容错性。
MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由 Hadoop内部完成的。
4>.适合PB级以上海量数据的离线处理。
它适合离线处理而不适合在线处理。比如像毫秒级别的返回一个结果,MapReduce很难做到。
三.MapReduce缺点
MapReduce不擅长做实时计算、流式计算、DAG(有向图)计算。
1>.实时计算。
MapReduce无法像Mysql一样,在毫秒或者秒级内返回结果。
2>.流式计算。
流式计算的输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化。这是因为MapReduce自身的设计特点决定了数据源必须是静态的。
3>.DAG(有向图)计算。
多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。
四.MapReduce进程
一个完整的mapreduce程序在分布式运行时有三类实例进程:
1>.MrAppMaster:
负责整个程序的过程调度及状态协调。
2>.MapTask:
负责map阶段的整个数据处理流程。
3>.ReduceTask:
负责reduce阶段的整个数据处理流程。
五.MapReduce编程规范
用户编写的程序分成三个部分:Mapper,Reducer,Driver(提交运行mr程序的客户端)
1>.Mapper阶段
(1)用户自定义的Mapper要继承自己的父类
(2)Mapper的输入数据是KV对的形式(KV的类型可自定义)
(3)Mapper中的业务逻辑写在map()方法中
(4)Mapper的输出数据是KV对的形式(KV的类型可自定义)
(5)map()方法(maptask进程)对每一个<K,V>调用一次
2>.Reducer阶段
(1)用户自定义的Reducer要继承自己的父类
(2)Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
(3)Reducer的业务逻辑写在reduce()方法中
(4)Reducetask进程对每一组相同k的<k,v>组调用一次reduce()方法
3>.Driver阶段
整个程序需要一个Drvier来进行提交,提交的是一个描述了各种必要信息的job对象
六.Hadoop序列化
1>.为什么要序列化?
一般来说,“活的”对象只生存在内存里,关机断电就没有了。而且“活的”对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机。 然而序列化可以存储“活的”对象,可以将“活的”对象发送到远程计算机。
2>.什么是序列化?
序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储(持久化)和网络传输。
反序列化就是将收到字节序列(或其他数据传输协议)或者是硬盘的持久化数据,转换成内存中的对象。
3>.为什么不用Java的序列化?
ava的序列化是一个重量级序列化框架(Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,header,继承体系等),不便于在网络中高效传输。所以,hadoop自己开发了一套序列化机制(Writable),精简、高效。
4>.为什么序列化对Hadoop很重要?
因为Hadoop在集群之间进行通讯或者RPC调用的时候,需要序列化,而且要求序列化要快,且体积要小,占用带宽要小。所以必须理解Hadoop的序列化机制。
序列化和反序列化在分布式数据处理领域经常出现:进程通信和永久存储。然而Hadoop中各个节点的通信是通过远程调用(RPC)实现的,那么RPC序列化要求具有以下特点:
(1)紧凑:紧凑的格式能让我们充分利用网络带宽,而带宽是数据中心最稀缺的资
(2)快速:进程通信形成了分布式系统的骨架,所以需要尽量减少序列化和反序列化的性能开销,这是基本的;
(3)可扩展:协议为了满足新的需求变化,所以控制客户端和服务器过程中,需要直接引进相应的协议,这些是新协议,原序列化方式能支持新的协议报文;
(4)互操作:能支持不同语言写的客户端和服务端进行交互;
(5).常用数据序列化类型
5>.常用的数据类型对应的hadoop数据序列化类型
七.MapReduce案例实操
1>.编写mapper类
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E7%94%9F%E6%80%81%E5%9C%88/ 4 EMAIL:[email protected] 5 */ 6 package mapreduce.yinzhengjie.org.cn; 7 8 import org.apache.hadoop.io.IntWritable; 9 import org.apache.hadoop.io.LongWritable; 10 import org.apache.hadoop.io.Text; 11 import org.apache.hadoop.mapreduce.Mapper; 12 13 import java.io.IOException; 14 15 16 public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{ 17 18 Text k = new Text(); 19 IntWritable v = new IntWritable(1); 20 21 @Override 22 protected void map(LongWritable key, Text value, Context context) 23 throws IOException, InterruptedException { 24 25 // 1 获取一行 26 String line = value.toString(); 27 28 // 2 切割 29 String[] words = line.split(" "); 30 31 // 3 输出 32 for (String word : words) { 33 34 k.set(word); 35 context.write(k, v); 36 } 37 } 38 }
2>.编写Reduce类
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E7%94%9F%E6%80%81%E5%9C%88/ 4 EMAIL:[email protected] 5 */ 6 package mapreduce.yinzhengjie.org.cn; 7 8 import java.io.IOException; 9 import org.apache.hadoop.io.IntWritable; 10 import org.apache.hadoop.io.Text; 11 import org.apache.hadoop.mapreduce.Reducer; 12 13 public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{ 14 15 @Override 16 protected void reduce(Text key, Iterable<IntWritable> value, 17 Context context) throws IOException, InterruptedException { 18 19 // 1 累加求和 20 int sum = 0; 21 for (IntWritable count : value) { 22 sum += count.get(); 23 } 24 25 // 2 输出 26 context.write(key, new IntWritable(sum)); 27 } 28 }
3>.编写驱动类
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Hadoop%E7%94%9F%E6%80%81%E5%9C%88/ 4 EMAIL:[email protected] 5 */ 6 package mapreduce.yinzhengjie.org.cn; 7 8 import java.io.IOException; 9 import org.apache.hadoop.conf.Configuration; 10 import org.apache.hadoop.fs.Path; 11 import org.apache.hadoop.io.IntWritable; 12 import org.apache.hadoop.io.Text; 13 import org.apache.hadoop.mapreduce.Job; 14 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; 15 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; 16 17 public class WordcountDriver { 18 19 public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { 20 /** 21 * 配合Hadoop的环境变量,如果没有配置可能会抛异常:“ERROR util.Shell: Failed to locate the winutils binary in the hadoop binary path”, 22 * 还有一件事就是你的HADOOP_HOME的bin目录下必须得有winutils.exe 23 * 24 */ 25 System.setProperty("hadoop.home.dir", "D:\\yinzhengjie\\softwares\\hadoop-2.7.3"); 26 27 //获取配置信息 28 Configuration conf = new Configuration(); 29 Job job = Job.getInstance(conf); 30 31 //设置jar加载路径 32 job.setJarByClass(WordcountDriver.class); 33 34 //设置map和Reduce类 35 job.setMapperClass(WordcountMapper.class); 36 job.setReducerClass(WordcountReducer.class); 37 38 //设置map输出 39 job.setMapOutputKeyClass(Text.class); 40 job.setMapOutputValueClass(IntWritable.class); 41 42 //设置Reduce输出 43 job.setOutputKeyClass(Text.class); 44 job.setOutputValueClass(IntWritable.class); 45 46 //设置输入和输出路径 47 FileInputFormat.setInputPaths(job, new Path(args[0])); 48 FileOutputFormat.setOutputPath(job, new Path(args[1])); 49 50 //等待job提交完毕 51 boolean result = job.waitForCompletion(true); 52 53 System.exit(result ? 0 : 1); 54 } 55 }
八.本地测试
九.集群测试