什么是序列化:序列化就是将内存中的对象转化为其他可存储文件或可跨越计算机传输数据流的一种方式。
什么是反序列化:反序列化就是将收到的字节序列或者磁盘中的持久化数据转化为内存中的对象。
为什么要序列化:由于在运行程序的过程中,保存在内存中的对象会因为断电而丢失,或者在分布式系统中,对象需要由一台计算机传递给其他计算机进行计算,所以对象需要转化为文件或实际可传输的数据流。
为什么不用Java的序列化方式:Java序列化的方式实现java.io.Serializable接口,但是java的序列化是一个重量级序列化框架,他会附带很多额外的信息。因此Hadoop实现了自己的序列化机制,即实现org.apache.hadoop.io.Writable接口。
Hadoop序列化的特点:
1、紧凑:高效使用存储空间
2、快速:读写数据的额外开销小
3、可扩展:随着通信协议的升级而可升级
4、互操作:支持多种语言的交互
环境:Hadoop-3.0.0、IDEA、Maven
原始数据:http://链接:https://pan.baidu.com/s/1ohDP3-IeIQwcPpeUKWK95g?pwd=yyds 提取码:yyds
准备工作可参照:https://blog.csdn.net/m0_63716485/article/details/127597324?spm=1001.2014.3001.5502
由于Hadoop序列化的方法时实现org.apache.hadoop.io.Writable接口,因此我们首先编写writable类实现Writable接口:
import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class writable implements Writable{
//数据 1 13736230513 192.196.100.1 www.atguigu.com 2481 24681 200
public writable() {
//空参构造
}
private long value1;
private long value2;
private long sumv;
public long getSumv() {
return sumv;
}
public void setSumv() {
this.sumv = this.value1+this.value2;
}
public long getValue1() {
return value1;
}
public void setValue1(long value1) {
this.value1 = value1;
}
public long getValue2() {
return value2;
}
public void setValue2(long value2) {
this.value2 = value2;
}
public void write(DataOutput dataOutput) throws IOException {
//重写序列化方法
dataOutput.writeLong(value1);
dataOutput.writeLong(value2);
dataOutput.writeLong(sumv);
}
public void readFields(DataInput dataInput) throws IOException {
//重写反序列化方法
this.value1=dataInput.readLong();
this.value2=dataInput.readLong();
this.sumv=dataInput.readLong();
}
@Override
public String toString() {
return value1 + "\t" + value2 + "\t" + sumv + '\t';
}
}
注意1:在重写序列化方法和反序列化方法时要注意顺序一致
Mapper类:
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class mapperx extends Mapper<LongWritable, Text,Text,writable>{
Text t=new Text();
writable w=new writable();
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, writable>.Context context) throws IOException, InterruptedException {
//获取对应行
String l=value.toString();
//分割
String s[]=l.split("\t");
//获取键值对
String a=s[1];
String b=s[s.length-3];
String c=s[s.length-2];
//封装
t.set(a);
w.setValue1(Long.parseLong(b));
w.setValue2(Long.parseLong(c));
w.setSumv();
//写出
context.write(t, w);
}
}
Reduce类:
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class reducerx extends Reducer<Text,writable,Text,writable> {
writable o=new writable();
@Override
protected void reduce(Text key, Iterable<writable> values, Reducer<Text, writable, Text, writable>.Context context) throws IOException, InterruptedException {
long totalvalue1=0;
long totalvalue2=0;
for(writable value:values){
totalvalue1+=value.getValue1();
totalvalue2+=value.getValue2();
}
o.setValue1(totalvalue1);
o.setValue2(totalvalue2);
o.setSumv();
context.write(key, o);
}
}
主程序入口:
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 Main {
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
//创建一个job
Job job=Job.getInstance(new Configuration());
job.setJarByClass(Main.class);
//创建job的mapper和输出的类型
job.setMapperClass(mapperx.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(writable.class);
//创建job的reduce和输出的类型
job.setReducerClass(reducerx.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(writable.class);
//创建job指定的输入和输出路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//执行任务
job.waitForCompletion(true);
}
}
注意2:在编写程序时要注意不要导错包
注意3:输入输出类型一致
结果展示: