上篇博客介绍了Hadoop核心组件之MapReduce,本篇主要介绍Hadoop的序列化,关注专栏《破茧成蝶——大数据篇》查看相关系列的文章~
目录
一、序列化概述
序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。反序列化就是将受到的字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象。
Java的序列化是一个重量级序列化框架(Serializable),一个对象被序列化之后,会附带很多额外的信息,例如:各种校验信息、Header等。不便于在网络中高效传输。所以Hadoop自己开发了一套序列化机制(Writable)。Hadoop序列化的特点:(1)可以高效的使用存储空间。(2)读写数据的额外开销小。(3)随着通信协议的升级而可升级。(4)支持多语言的交互。
二、序列化实例
2.1 数据与需求
首先先来看看数据吧,先分析下数据:
这是一段经过处理的Nginx后台日志信息,字段依次是:时间、版本、客户端ip、访问路径、状态、域名、服务端ip、size、响应时间。现在我们统计一下每一个客户端ip对应的总size,文件名称为nginx_log。
2.2 编写Bean对象
package com.xzw.hadoop.mapreduce.nginx;
import org.apache.hadoop.io.Writable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* @author: xzw
* @create_date: 2020/7/28 10:01
* @desc:
* @modifier:
* @modified_date:
* @desc:
*/
public class NginxBean implements Writable {//实现Writable接口
private long size;//size
//反序列化时,需要反射调用空参构造器,所以必须有空参构造器
public NginxBean() {
}
public void set(long size) {
this.size = size;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
/**
* 序列化方法
* @param dataOutput
* @throws IOException
*/
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeLong(size);
}
/**
* 反序列化方法:反序列化方法读取顺序必须跟序列化方法写顺序一致
* @param dataInput
* @throws IOException
*/
public void readFields(DataInput dataInput) throws IOException {
this.size = dataInput.readLong();
}
/**
* 编写toString方法,方便后续打印到文本
* @return
*/
@Override
public String toString() {
return size + "\t";
}
}
2.3 编写Mapper类
package com.xzw.hadoop.mapreduce.nginx;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* @author: xzw
* @create_date: 2020/7/28 10:30
* @desc:
* @modifier:
* @modified_date:
* @desc:
*/
public class NginxMapper extends Mapper<LongWritable, Text, Text, NginxBean> {
NginxBean nginxBean = new NginxBean();
Text text = new Text();
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//1、获取一行数据
String line = value.toString();
//2、切割字段
String[] fields = line.split("\t");
//3、封装对象
String clientIP = fields[2];//取出客户端的IP
long size = Long.parseLong(fields[fields.length - 2]);//取出size
text.set(clientIP);
nginxBean.set(size);
//4、写出
context.write(text, nginxBean);
}
}
2.4 编写Reducer类
package com.xzw.hadoop.mapreduce.nginx;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
* @author: xzw
* @create_date: 2020/7/28 10:39
* @desc:
* @modifier:
* @modified_date:
* @desc:
*/
public class NginxReducer extends Reducer<Text, NginxBean, Text, NginxBean> {
private NginxBean nginxBean = new NginxBean();
@Override
protected void reduce(Text key, Iterable<NginxBean> values, Context context) throws IOException, InterruptedException {
long sum_size = 0;
//1、遍历所有的数据,将需要的数据进行累加
for (NginxBean nginxBean: values) {
sum_size += nginxBean.getSize();
}
//2、封装对象
nginxBean.set(sum_size);
//3、写出
context.write(key, nginxBean);
}
}
2.5 编写Driver类
package com.xzw.hadoop.mapreduce.nginx;
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;
/**
* @author: xzw
* @create_date: 2020/7/28 10:48
* @desc:
* @modifier:
* @modified_date:
* @desc:
*/
public class NginxDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//输入输出路径
args = new String[]{"e:/input/nginx_log", "e:/output"};
//1、获取配置信息或者job实例
Job job = Job.getInstance(new Configuration());
//2、设置类路径
job.setJarByClass(NginxDriver.class);
//3、设置Mapper和Reducer
job.setMapperClass(NginxMapper.class);
job.setReducerClass(NginxReducer.class);
//4、设置Mapper和Reducer的输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(NginxBean.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NginxBean.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);
}
}
2.6 测试
运行Driver,得到测试结果:
当然,也可以提交到集群中,具体打包方法在这就不再赘述了,可以参考上篇博客《九、Hadoop核心组件之MapReduce》中的打包运行方式。
至此,本文就讲解完了,你们在这个过程中遇到了什么问题,欢迎留言,让我看看你们遇到了什么问题~