Hadoop学习记录(4)|MapReduce原理|API操作使用
MapReduce概念
MapReduce是一种分布式计算模型,由谷歌提出,主要用于搜索领域,解决海量数据计算问题。
MR由两个阶段组成:Map和Reduce,用户只需要实现map()和reduce()两个函数实现分布式计算。
这两个函数的形参是key,value对,表示函数的输入信息。
MP执行流程
客户端提交给jobtracker,jobtracker分配给tasktracker。
trasktracker会对任务进行mapper和reducer操作。
MapReduce原理
一个map输入k1、v1,数据由输入文件中获取
map会把数据提交到每一个shuffle,最后输出到reducer任务。
reducer任务的数量跟mapper发送到shuffle的数量是一致的。
map任务处理
1.1、读取输入文件内容,解析成key,value对。对输入文件的每一个解析成key\value对。每个键值对调用一次map函数。
1.2、写自己的逻辑,对输入的key、value处理,转换成新的key、value输出。
1.3、对输出的key、value进行分区
1.4、对不同分区的数据按照key进行排序、分组。相同key的value放到一个集合中。
1.5、(可选)分组后对数据进行规约
reduce任务处理
2.1、对多个map任务的输出按照不同的分区通过网络拷贝到reduce节点。
2.2、对多个map任务输出进行合并、排序。写reduce函数自己的逻辑,对输入key、value处理,转换成新的key、value输出。
2.3、把输出的结果保存到HDFS中。
MapReduce执行过程
1.1.读取hdfs中文件,每个解析成<k,v>。每一个键值对调用一次map函数。
解析成两个<k,v>,分别<0,hello you><10,hello me>。调用map函数两次。
k是每行的开始位置,v则示每行的文本内容。
1.2.覆盖map()函数,接收1.1产生的<k,v>,进行处理,转换新的<k,v>输出。
1.3.对1.2输出的<k,v>进行分区
public void map(k,v,context){
String[] split = v.toString().split(“ ”);
for(String str : split){
context.write(str,1);
}
}
1.4.对不同分区中的数据进行排序(按照k)、分组,分别将key的value放到一个集合中。
map输出后的数据是:<hello,1]>,<you,1>,<hello,1>,<me,1>
排序后: <hello,1]>, <hello,1>,<you,1>,<me,1>
分组后:<hello,{1,1}>,<you,{1}>,<me,{1}>
1.5.(可选)对分组后的数据进行规约。
2.1.多个map任务的输出按照不同的分区,通过网络copy到不同的reduce节点上。
2.2.对多个map的输出进行合并,排序,覆盖reduce函数,接收的是分组的数据,实现自己的业务逻辑,处理后产生新的<k,v>输出。
reduce函数被调用3次,跟分组次数一致。
public void reduce(k,vs,context){
long sum =0L;
for(long num:vs){
sum +=num;
}
context.write(k,sum);
}
2.3.设置任务执行,对reduce输出的<k,v>保存到hdfs中。
job.waitForCompletion(true);
整个流程我分了四步。简单些可以这样说,每个map task都有一个内存缓冲区,存储着map的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式存放到磁盘,当整个map task结束后再对磁盘中这个map task产生的所有临时文件做合并,生成最终的正式输出文件,然后等待reduce task来拉数据。
MapReduce提交的源代码分析
waitForCompletion函数中的submit方法连接和提交到jobtracker。
在eclipse中写的代码如何提交到JobTracker中的哪?
答(1)eclipse中调用的job.waitForCompletion(true),实际调用的是JobClient中的提交方法。
contect()
info = jobClient.submitJobInternal(conf)
(2)在contect()中,实际创建了一个JobClient对象,在调用该对象的构造方法时,获得了JobTracker的客户端代理对象JobSubmissionProtocol
jobSubmissionProtocol实现类是JobTracker
(3)在jobClient.submitJobInternal(conf)方法中,调用了jobSubmissionProtocol.submitJob()
即,执行的是JobTracker.submitJob(..)
Hadoop基本类型
Hadoop数据类型必须实现Writable接口。
Long LongWritable
Boolean BooleanWritable
String Text
Integer IntWritable
Java类型转换为Hadoop基本类型:
直接调用hadoop类的构造方法,或者调用set()方法
new IntWritable(123)
Hadoop类型转换成Java类型:
text需要调用toString方法
其他类型调用get()方法
使用Hadoop自定义类型处理手机上网流量
1、自定义类
class KpiWritable implements Writable{
long upPackNum;
long downPackNum;
long upPayLoad;
long downPayLoad;
public KpiWritable() {}
public KpiWritable(String upPackNum,String downPackNum,String upPayLoad,String downPayLoad){
this.upPackNum = Long.parseLong(upPackNum);
this.downPackNum = Long.parseLong(downPackNum);
this.upPayLoad = Long.parseLong(upPayLoad);
this.downPayLoad = Long.parseLong(downPayLoad);
}
@Override
public void write(DataOutput out) throws IOException {
//序列化出去
out.writeLong(upPackNum);
out.writeLong(downPackNum);
out.writeLong(upPayLoad);
out.writeLong(downPayLoad);
}
@Override
public void readFields(DataInput in) throws IOException {
//顺序和写出去一样
this.upPackNum = in.readLong();
this.downPackNum = in.readLong();
this.upPayLoad = in.readLong();
this.downPayLoad = in.readLong();
}
@Override
public String toString() {
return upPackNum+"\t"+downPackNum+"\t"+upPayLoad+"\t"+downPayLoad;
}
2、自定义Map
static class MyMapper extends Mapper<LongWritable, Text, Text, KpiWritable>{
protected void map(LongWritable k1, Text v1,
org.apache.hadoop.mapreduce.Mapper<LongWritable,Text,Text,KpiWritable>.Context context)
throws IOException, InterruptedException {
//处理接收的数据
String[] splits = v1.toString().split("\t");
//获取手机号
String msisdn = splits[1];
Text k2 = new Text(msisdn);
KpiWritable v2 = new KpiWritable(splits[6],splits[7],splits[8],splits[9]);
//写入context中交过reduce执行
context.write(k2, v2);
}
}
3、自定义Reduce
static class MyReduce extends Reducer<Text, KpiWritable, Text, KpiWritable>{
protected void reduce(Text k2, Iterable<KpiWritable> v2s,org.apache.hadoop.mapreduce.Reducer<Text, KpiWritable, Text, KpiWritable>.Context context)
throws IOException, InterruptedException {
/**
* k2 表示不同的手机号
* v2s 表示该手机号不同时段流量集合
*/
//定义计数器
long upPackNum = 0L;
long downPackNum = 0L;
long upPayLoad = 0L;
long downPayLoad = 0L;
//遍历合并数据
for(KpiWritable kpi : v2s){
upPackNum += kpi.upPackNum;
downPackNum += kpi.downPackNum;
upPayLoad += kpi.upPayLoad;
downPayLoad += kpi.downPayLoad;
}
//封装到对象中
KpiWritable v3 = new KpiWritable(upPackNum+"", downPackNum+"", upPayLoad+"", downPayLoad+"");
//写入context中
context.write(k2, v3);
}
}
4、写驱动程序
static final String INPUT_PATH = "hdfs://h1:9000/wlan";
static final String OUT_PATH = "hdfs://h1:9000/wlan_out";
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
FileSystem fileSystem = FileSystem.get(new URI("hdfs://h1:9000/"), conf);
Path outPut = new Path(OUT_PATH);
if(fileSystem.exists(outPut)){
fileSystem.delete(outPut,true);
}
/**
* 1.1、指定输入文件路径
* 1.1.1. 指定那个类来格式化输入文
* 1.2、指定自定义的Mapper类
* 1.2.1.指定输出<k2,v2>的类型
* 1.3、指定分区
* 1.4、排序分区(TODO)
* 1.5、(可选)合并
* 2.1、多个map任务的输出,通过网络copy到不同的reduce节点上,这个操作由hadoop自动完成
* 2.2、指定定义的reduce类
* 2.2.1.指定输出<k3,v3>类型
* 2.3、指定输出位置
* 2.3.1、设置输出文件的格式化类
*
* 最后吧代码提交到JobTracker执行
*/
//创建Job任务
Job job = new Job(conf,KpiApp.class.getSimpleName());
//设置输入路径
FileInputFormat.setInputPaths(job, INPUT_PATH);
//设置输入数据使用的格式化类
job.setInputFormatClass(TextInputFormat.class);
//设置自定义Map类
job.setMapperClass(MyMapper.class);
//设置Map类输出的key和value值类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(KpiWritable.class);
//设置分区类
job.setPartitionerClass(HashPartitioner.class);
//设置任务数
job.setNumReduceTasks(1);
//设置自定义Reduce类
job.setReducerClass(MyReduce.class);
//设置输入数据使用的格式化类
job.setInputFormatClass(TextInputFormat.class);
//设置Reduce输出的key和value值类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(KpiWritable.class);
//设置输出文件位置
FileOutputFormat.setOutputPath(job, outPut);
//设置将任务提交到JobTracker
job.waitForCompletion(true);
}
MapReduce 0.x API区别
hadoop版本0.x
1、包一般是mapred。
2、使用是JobConf类创建Job任务。
3、使用JobClient.runJob(jobConf)提交任务。
4、自定义类需要继承MapReduceBase实现Mapper和Reducer接口。
hadoop版本1.x
1、包一般是mapreduce。
2、使用的Job类创建任务。
3、ob.waitForCompletion(true)提交任务。
4、自定义类只需要继承Mapper和Reducer类。
命令行运行指定参数
hadoop jar WordCount.jar hdfs://h1:9000/hello hdfs://h1:9000/cmd_out
跟eclipse直接运行的代码区别:
1、类需要继承org.apache.hadoop.conf.Configured,并实现org.apache.hadoop.util.Tool。
2、以前main方法中写的驱动程序卸载覆写的run方法中。
3、run()方法中
job.setJarByClass(CmdWordCount.class);
4、输入输出字符串定义为全局空字符串
5、main方法中使用org.apache.hadoop.util.ToolRunner的run方法,传入new CmdWordCount()和args。args是main方法接收的字符串数组。
6、在覆写的run方法中把接收到的args数组提取并赋值给INPUT和OUTPUT的路径
INPUT_PATH = agrs0[0];
OUTPUT_PATH = args0[1];
6、打包时一定要记得选择输出类。
Hadoop计数器
File Input Format Counters
Bytes Read=19 读取文件字节数
Map-Reduce Framework
Map output materialized bytes=65
1#Map input records=2 读取记录行
Reduce shuffle bytes=65
Spilled Records=8
Map output bytes=51
Total committed heap usage (bytes)=115675136
5#Combine input records=0 Map合并/规约输入
SPLIT_RAW_BYTES=85
3# Reduce input records=4 reduce输入行
4#Reduce input groups=3 Reduce输入组数
Combine output records=0 Map合并/规约输出
Reduce output records=3 Reduce输出记录
2#Map output records=4 Map输出行
通过计数器数可以检查出Map还是Reduce出现问题。
舆情监督示例,使用自定义计数器监控出现次数。
//自定义计数器
Counter helloCounter = context.getCounter("Sensitive Words", "hello");
String line = v1.toString();
if(line.contains("hello")){
helloCounter.increment(1L);
}
Combine操作
为什么使用Combine?
Combiner发生在Map端。对数据进行规约处理,数据量变小了,传送到reduce的数据量变小,传输时间变短,作业整体时间变短。
为什么Combine不作为MapReduce的标配,而是可选配置?
因为不是所有的算法都适合使用Combine处理,例如求平均数。
适用于求和
Combine本身已经执行了Reduce操作,为什么Reduce阶段还要执行reduce操作?
combine操作发送在map端,处理一个任务所接收的文件中的数据,不能跨map任务;只有reduce可以接收多个map任务处理数据。
设置参数
job.setCombinerClass(MyCombiner.class);
MyCombiner.class可以使用Reduce
Partitioner编程
对输出的key,value进行分区。
指定自定义partition类,自定义类需要继承HashPartitioner类。覆盖getPartition方法。
分区的实例必须打成Jar包。
作用:
1、根据业务需要,产生多个输出文件。
2、多个reduce任务在运行,提高整体job的运行效率。
根据实际情况来使用,如果有5台机器,而分成100个分区来运行或出现延迟和整体效率低问题。因为需要排队运行!
主要代码:
设置成打包运行 job.setJarByClass(KpiApp.class);
设置分区job.setPartitionerClass(MyPartitioner.class);
设置Reduce任务数 job.setNumReduceTask(2);
自定义Partitioner类需要继承HashPartition类,泛型使用K2,V2的类型。覆写getPartition方法。
排序和分组
排序
在map和reduce阶段进行排序时,比较的是k2。v2是不参与排序比较。如果让v2也进行排序,需要将k2和v2组装成心的类,作为k2,才能参与比较。
新类需要实现WritableCompareble,覆写readFilds、write、compareTo、hasCode、equals方法。
在自定义map程序中将k2,v2封装到新类中,当做k2写入context。
编写驱动main方法时,设置map输出的类型(job.setMapOutputKeyClass(new.class))
分组
按照K2进行比较,这个k2是分装到自定义类的k2。
自定义分组类实现RewComparetor,覆写compare方法。
public int compare(NewK2 o1, NewK2 o2) {
return (int) (o1.k2 - o2.k2);
}
/**
* @param b1 表示第一个参与比较的字节数组
* @param s1 表示第一个参与比较的字节数组的起始位置
* @param l1 表示第一个参与比较的字节数组的偏移量
*
* @param b2 表示第二个参与比较的字节数组
* @param s2 表示第二个参与比较的字节数组的起始位置
* @param l2 表示第二个参与比较的字节数组的偏移量
*
*/
public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2,
int l2) {
return WritableComparator.compareBytes(b1, s1, 8, b2, s2, 8);
}
job任务设置分组比较组 job.setGroupComparatorClass(MyGroup.class);
Shuffle
MapReduce的核心,俗称洗牌、打乱。
shuffle在map任务传送到reduce任务之间。
Map端
1、每个map有一个环形内存缓冲区,用于存储任务的输出,默认100MB,如果达到法制80MB后台线程会把内容写到指定磁盘(mapred.local.dir)下的新建的溢出文件。
2、写入磁盘钱,要partition、sort。如果有combiner,combine后写入。
3、最后记录完成,合并全部溢写文件为一个分区且排序的文件。
Reduce端
1、Reduce通过Http方式得到输出文件的分区。
2、TaskTracker为分区文件运行Reduce任务。复制阶段把Map输出复制到Reducer的内存或磁盘。一个Map任务完成,Reduce开始复制输出。
3、排序阶段合并map输出,最后运行Reduce阶段。
MapReduce常见算法
单词计数
数据去重
排序
TopK
选择
投影
分组
多表连接
单边关联
Hadoop学习记录(4)|MapReduce原理|API操作使用的更多相关文章
- 【Hadoop学习之六】MapReduce原理
一.概念MapReduce:"相同"的key为一组,调用一次reduce方法,方法内迭代这一组数据进行计算 块.分片.map.reduce.分组.分区之间对应关系block > ...
- Lua和C++交互 学习记录之二:栈操作
主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3 参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 1 ...
- Elasticsearch7.X 入门学习第二课笔记----基本api操作和CRUD
原文:Elasticsearch7.X 入门学习第二课笔记----基本api操作和CRUD 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链 ...
- Hadoop学习记录(3)|HDFS API 操作|RPC调用
HDFS的API操作 URL方式访问 package hdfs; import java.io.IOException; import java.io.InputStream; import java ...
- hadoop 学习笔记:mapreduce框架详解
开始聊mapreduce,mapreduce是hadoop的计算框架,我学hadoop是从hive开始入手,再到hdfs,当我学习hdfs时候,就感觉到hdfs和mapreduce关系的紧密.这个可能 ...
- Hadoop学习笔记:MapReduce框架详解
开始聊mapreduce,mapreduce是hadoop的计算框架,我学hadoop是从hive开始入手,再到hdfs,当我学习hdfs时候,就感觉到hdfs和mapreduce关系的紧密.这个可能 ...
- 【Big Data - Hadoop - MapReduce】hadoop 学习笔记:MapReduce框架详解
开始聊MapReduce,MapReduce是Hadoop的计算框架,我学Hadoop是从Hive开始入手,再到hdfs,当我学习hdfs时候,就感觉到hdfs和mapreduce关系的紧密.这个可能 ...
- Hadoop入门进阶课程5--MapReduce原理及操作
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博主为石山园,博客地址为 http://www.cnblogs.com/shishanyuan ...
- MapReduce原理及操作
注意:本实验是对前述实验的延续,如果直接点开始实验进入则需要按先前学习的方法启动hadoop 部署节点操作系统为CentOS,防火墙和SElinux禁用,创建了一个shiyanlou用户并在系统根目录 ...
随机推荐
- [Python][flask][flask-wtf]关于flask-wtf中API使用实例教程
简介:简单的集成flask,WTForms,包括跨站请求伪造(CSRF),文件上传和验证码. 一.安装(Install) 此文仍然是Windows操作系统下的教程,但是和linux操作系统下的运行环境 ...
- About building ant & install ant on centos7 {ant source code 1.94}
hamcrest-junit-2.0.0.0.jar java-hamcrest-2.0.0.0.jar copy to ant-sourceCodeDir/lib/o ...
- python实用函数
dir([obj]) 显示对象属性, 无参数显示全局变量的名字 help([obj]) 显示对象的文档字符串 int(obj) 将一个对象转换为整数 len(obj) 返回对象的长度 range([[ ...
- ASP.NET 学习小记 -- “迷你”MVC实现(1)
ASP.NET 由于采用了管道式设计,具有很好的扩展性.整个ASP.NET MVC应用框架就是通过扩展ASP.NET实现的.通过ASP.NET的管道设计,我们知道,ASP.NET的扩展点主要是体现在H ...
- zoom 用法
from: http://www.jb51.net/css/40285.html 其实Zoom属性是IE浏览器的专有属性,Firefox等浏览器不支持.它可以设置或检索对象的缩放比例.除此之外,它还有 ...
- 一步步学习ASP.NET MVC3 (6)——@helper,@functions
请注明转载地址:http://www.cnblogs.com/arhat 在前一章中,我们讲述了View如何从Action中获得数据,并显示出来,但随着需求的变化,我们可能要对View中显示的数据作出 ...
- 制作第一个UI图集
按钮分有两种形式,一种是普通按钮,也就是一张没有文字的按钮图片,在需要用时,就在上面写上不同的.当前所需要的文字.量一种按钮则是图片按钮,这种按钮的特点是整个按钮就是一张图片,它既是按钮也是图片. 在 ...
- 重启Finder
解决Finder卡死的问题! 方法一:在Dock 图标上操作 按住 Option 键并右键点按 Finder 图标,选择菜单中的“重新开启” 方法二:在终端里操作 打开终端(应用程序 – 实用工具), ...
- 图片生成操作属性导致WP内存溢出解决办法
在开发的项目中,发现经常会出现异常 “内存溢出,不能再继续执行程序”,通过搜索一些国外的文章,发现原来是由于项目中的图片比较多,而生存操作设为了“内容”.通过设置图片的生成操作为“无”,复制操作为“如 ...
- Android RelativeLayout 属性
// 相对于给定ID控件 android:layout_above 将该控件的底部置于给定ID的控件之上; android:layout_below 将该控件的底部置于给定ID的控件之下; andro ...