一、概述
定义:MapReduce是一个分布式运算程序的编程框架,是接触到的第一个编程框架。在框架下编程体验:非常不透明,大部分功能都已经实现了。核心功能:将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并运行在一个Hadoop集群上。优点:简单实现一些接口,我们可以非常快速的开发出一个分布式程序。缺点:慢,因为资源占用相对低。在计算机中,时间和空间是一对矛盾的概念,想要快速就要占用多的空间,想节省资源就要多花费时间。MapReduce框架用的很少,但思想一致。核心编程思想:map 映射,把原始的数据文件映射成希望的形式,把不好处理的数据变的好处理,映射阶段倾向于交给很多个map来处理。各个映射文件间没有关系。reduce 规约,把多个map文件整合到一个reduce中,进行输出。最简单的MapReduce:wordcount,一个大文件,想要统计其中的单词数量不好统计,所以通过map把文件映射成不同的(K,V)值,K是各种单词,v = 1,表示每一个单词出现了一次。每个map映射出一堆东西,所有结果汇总到一个reduce中。执行官方wordcount程序:
/opt/module/hadoop-3.1.3/share/hadoop/mapreduce/文件夹下的hadoop-mapreduce-examples-3.1.3.jar文件提供了官方给出的一些 示例程序,执行这个文件中的一些程序完成测试。
首先将程序 提交到yarn上,yarn jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount(想要运行的程序名称) /README.txt(源文件) /output(hdfs不存在的文件夹)
常用数据序列化类型:
在ieda中自定义wordCount程
Mapper
package com.hike.mr.wordcount; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; public class WcMapper extends Mapper{ private Text word = new Text(); //拆分后的一个一个的单词 private IntWritable one = new IntWritable(1); //数字1 @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { //拿到一行数据 String line = value.toString(); //把一行拆成很多个单词 String[] words = line.split(" "); //将(单词,1)写回框架,调用很多次write方法,不要在方法内new对象 for(String wd : words){ this.word.set(wd); context.write(this.word, this.one); } } }
Reducer
package com.hike.mr.wordcount; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class WcReducer extends Reducer{ private IntWritable result = new IntWritable(); @Override protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException { //累加 int sum = 0; for(IntWritable value : values){ //同一个单词 sum += value.get(); //将包装的数据取出来 } //包装结果并写出去 result.set(sum); //将数字包装 context.write(key,result); } }
Driver
package com.hike.mr.wordcount;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WcDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//1.获取job实例
Job job = Job.getInstance(new Configuration());
//2.设置jar包,分布式程序,很多程序需要执行此命令
job.setJarByClass(WcDriver.class);
//3.设置Mapper和Reducer
job.setMapperClass(WcMapper.class);
job.setReducerClass(WcReducer.class);
//4.设置Map和Reducer的输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//5.设置输入输出文件
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//6.提交job
boolean b = job.waitForCompletion(true);
System.exit(b ? 0 : 1);
}
}
将maven项目打包好的jar包上传到服务器,执行
yarn jar mapreduce001-1.0-SNAPSHOT.jar(jar包名称) com.hike.mr.wordcount.WcDriver(Driver类的全引用) /LICENSE.txt(输入的文件) /output1(输出的文件【要求之前不存在的】)
常用数据序列化类型:
在idea执行自定义的wordcount程序:创建Maven程序,导入依赖和log4j2.xml,编写Mapper、Reducer、Driver类,打包,将jar包上传到服务器,执行。
二、Hadoop序列化
序列化概述
什么是序列化:把内存中“活的”的对象,转换成字节二进制序列,叫做序列化。序列化之后可以存储到磁盘上(持久化),可以通过网络传送(网络传输)。举个例子,当画家看到美丽的风景时,他将风景画成了一幅画,存储到他的画册中,并将这幅画供其他人查看。其中,风景变为画的过程称为序列化,画到画册中,称为持久化,供其他人观看,称为网络传输。为什么要序列化:一般来说,“活的”对象只存储在内存里,关机断电就没有了。而且,只能由本地的进程使用,不能别发送到网络上的另一台计算机上。为什么不使用java的序列化:在大数据背景下java的序列化不再适用,因为java序列化是一个重量级序列化框架,一个对象被序列化后,会附带很多额外信息(各种校验信息,Header,继承体系等),在网络中传送效率低,所以hadoop开发了一套序列化机制(Writable),只序列化必要的数据,如学生类中包含name,age,一些方法,那么hadoop之序列化name,age等必要信息,其他诸如继承体系等都不会被序列化,特点是紧凑(高效使用存储空间)、快速(读写数据的额外开销小)、可扩展(随着通信协议的升级而升级)、互操作(支持多语言的交互)。自定义bean对象实现序列化
在Hadoop中想要用自定义的bean对象需要提供一个无参构造器,因为其会在框架中通过反射的方式调用无参构造器来构造对象,使用默认的无参构造器也可以。
FlowBean
package com.hike.mr.flow;
import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
//想要在框架中使用需要实现接口
public class FlowBean implements Writable {
private long upFlow;
private long downFlow;
private long sumFlow;
@Override
public String toString(){
return upFlow + "/t" + downFlow + "/t" + sumFlow;
}
public void set(long upFlow,long downFlow){
this.upFlow = upFlow;
this.downFlow = downFlow;
this.sumFlow = upFlow + downFlow;
}
public long getUpFlow() {
return upFlow;
}
public void setUpFlow(long upFlow) {
this.upFlow = upFlow;
}
public long getDownFlow() {
return downFlow;
}
public void setDownFlow(long downFlow) {
this.downFlow = downFlow;
}
public long getSumFlow() {
return sumFlow;
}
public void setSumFlow(long sumFlow) {
this.sumFlow = sumFlow;
}
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeLong(upFlow);
dataOutput.writeLong(downFlow);
dataOutput.writeLong(sumFlow);
}
public void readFields(DataInput dataInput) throws IOException {
this.upFlow = dataInput.readLong();
this.downFlow = dataInput.readLong();
this.sumFlow = dataInput.readLong();
}
}
FlowMapper
package com.hike.mr.flow; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; public class FlowMapper extends Mapper{ private Text Phone = new Text(); private FlowBean flow = new FlowBean(); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { //拿到一行数据 String line = value.toString(); //切分 String[] fields = line.split("/t"); //封装 Phone.set(fields[1]); flow.set( Long.parseLong(fields[fields.length-3]), //upflow Long.parseLong(fields[fields.length-2]) //downflow ); context.write(Phone, flow); } }
FlowReducer
package com.hike.mr.flow; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class FlowReducer extends Reducer{ private FlowBean flow = new FlowBean(); @Override protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException { //累加流量 long sumUpFlow = 0; long sumDownFlow = 0; for (FlowBean value : values) { sumUpFlow += value.getUpFlow(); sumDownFlow += value.getDownFlow(); } //封装Flow类型 flow.set(sumUpFlow,sumDownFlow); context.write(key,flow); } }
FlowDriver
package com.hike.mr.flow;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class FlowDriver {
// static {
// System.load("F:\develop\lib\hadoop\bin\hadoop.dll");
// System.load("F:\develop\lib\hadoop\bin\hdfs.dll");
// }
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Job job = Job.getInstance(new Configuration());
job.setJarByClass(FlowDriver.class);
job.setMapperClass(FlowMapper.class);
job.setReducerClass(FlowReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class);
FileInputFormat.setInputPaths(job,new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
boolean b = job.waitForCompletion(true);
System.exit(b ? 0 : 1);
}
}



