目录
数据清洗(ETL)
定义
用来描述将数据从来源端经过抽取(Extract)、转换(Transform)、加载(Load)至目的端的过程。ETL 一词较常用在数据仓库,但其对象并不限于数据仓库
MapReduce里的ETL
在运行核心业务 MapReduce 程序之前,往往要先对数据进行清洗,清理掉不符合用户要求的数据。清理的过程往往只需要运行 Mapper 程序,不需要运行 Reduce 程序。
案例:去除日志中字段个数小于等于 11 的日志
Map部分代码
package com.atguigu.mapreduce.weblog;
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class WebLogMapper extends Mapper<LongWritable, Text, Text, NullWritable>{
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 1 获取1行数据
String line = value.toString();
// 2 解析日志
boolean result = parseLog(line,context);
// 3 日志不合法退出
if (!result) {
return;
}
// 4 日志合法就直接写出
context.write(value, NullWritable.get());
}
// 2 封装解析日志的方法
private boolean parseLog(String line, Context context) {
// 1 截取
String[] fields = line.split(" ");
// 2 日志长度大于11的为合法
if (fields.length > 11) {
return true;
}else {
return false;
}
}
}
MapReduce开发总结
1.输入数据接口:InputFormat
- 默认使用的实现类是:TextInputFormat
- TextInputFormat的功能逻辑是:一次读一行文本,然后将该行的起始偏移量作为key,行内容作为value返回。
- CombineTextInputFormat可以把多个小文件合并成一个切片处理,提高处理效率。
2.逻辑处理接口:Mapper
- 用户根据业务需求实现其中三个方法:setup(初始化) map(业务逻辑) cleanup (关闭资源)
3.Partitioner分区
- 有默认实现 HashPartitioner,逻辑是根据key的哈希值对numReduces取模来返回一个分区号;
key.hashCode()&Integer.MAXVALUE % numReduces
- 如果业务上有特别的需求,可以自定义分区。
4.Comparable排序
- 当我们用自定义的对象作为key来输出时,就必须要实现WritableComparable接口,重写其中的compareTo()方法。
- 部分排序:对最终输出的每一个文件进行内部排序。
- 全排序:对所有数据进行排序,通常只有一个Reduce()
- 二次排序:排序的条件有两个。
5.Combiner合并
Combiner合并可以提高程序执行效率,减少IO传输。但是使用时必须不能影响原有的业务处理结果。
在map端完成聚合,是解决数据倾斜的一种方法。
6.逻辑处理接口:Reducer
用户根据业务需求实现其中三个方法:reduce() setup() cleanup ()
7.输出数据接口:OutputFormat
- 默认实现类是TextOutputFormat,功能逻辑是:将每一个KV对,向目标文本文件输出一行。
- 用户还可以自定义OutputFormat。
Hadoop数据压缩
优劣处
压缩的优点:以减少磁盘IO、减少磁盘存储空间。
压缩的缺点:增加CPU开销。
原则
(1)运算密集型的Job,少用压缩
(2)IO密集型的Job,多用压缩
MR支持的压缩编码
压缩方式选择
压缩方式选择时重点考虑:压缩/解压缩速度、压缩率(压缩后存储大小)、压缩后是否可以支持切片。
压缩位置选择
输入端采用压缩
无需显示指定使用的编解码方式,Hadoop自动检查文件扩展名,如果扩展名能够匹配,就会用恰当的编解码方式对文件进行压缩和解压。
如果数据量小于块大小,则考虑速度比较快的LZO/Snappy
数据量非常大,则考虑支持切片的Bzip2和LZQ
Mapper输出采用压缩
为了减少MapTask和ReduceTask的网络IO,考虑速度快的LZO/Snappy
// 开启map端输出压缩
conf.setBoolean("mapreduce.map.output.compress", true);
// 设置map端输出压缩方式
conf.setClass("mapreduce.map.output.compress.codec", BZip2Codec.class,CompressionCodec.class);
Reducer输出采用压缩
如果数据永久保存,考虑压缩率比较高的Bzip2和Gzip。
如果作为下一个MapReduce输入,需要考虑数据量和是否支持切片。
// 设置reduce端输出压缩开启
FileOutputFormat.setCompressOutput(job, true);
// 设置压缩的方式
FileOutputFormat.setOutputCompressorClass(job, BZip2Codec.class);