MapReduce
输入格式-InputFormat
- InputFormat发生在Mapper之前,用于对数据进行切分和读取,会将读取到的数据传递给MapTask处理。所以InputFormat读取到的数据是什么格式,Mapper接收到的数据就是什么格式
- 作用 1. getSplits :对文件进行切片处理2. createRecordReader :创建输入流读取文件
- 默认情况下,MapReduce中使用的输入格式是 TextInputFormat , TextInputFormat 继承了 FileInputFormat 。需要注意的是, FileInputFormat 负责切片, TextInputFormat 负责读取
- FileInputFormat 切片过程中需要注意的问题: 1. 默认情况下,minSplitSize=1B,maxSplitSize=Long.MAX_VALUE2. 在MapReduce中, _ 开头的文件默认是隐藏文件不处理3. 如果当前文件是一个空文件,那么这个文件本身就是一个切片4. 在MapReduce中,文件有可切和不可切的区别。大部分情况下,文件是可切的,但如果是压 缩文件,那么不一定可切5. 如果文件不可切,那么这整个文件就是一个切片6. 默认情况下,Split和Block等大7. 如果需要调大SplitSize,那么需要调大minSize;如果需要调小SplitSize,那么需要调小 maxSize8. 切片过程中需要 SPLIT_SLOP ,默认值是1.1。当 bytesRemaining/splitSize >SPLIT_SLOP 才会继续切片。所以,如果一个文件是520M,那么对应了5个Block(4128+8),对应了4个Split(3128+136)
- TextInputFormat 读取过程中需要注意的问题: 1. TextInputFormat在读取文件之前会先判断文件是否可切:先获取文件的压缩编码,判断压 缩编码是否为空。如果压缩编码为空,那么说明不是压缩文件,该文件可切;如果压缩编码 不为空,那么判断是否是一个可切分的压缩文件2. 在MapReduce中,默认可切的压缩编码是 BZip2Codec ,后缀是 .bz23. 在读取文件的时候,会先获取每条数据之间的分隔符,默认情况下,分隔符是 \n 。可以通 过 textinputformat.record.delimiter 来指定每一条数据之间的间隔符号4. 确定好间隔符之后,会创建输入流 LineRecordReader 对象来读取数据5. 默认情况下,是按行读取数据,每一行数据最多允许有 Integer.MAX_VALUE 个字节6. 在读取文件的时候,会判断文件是否是一个压缩文件。如果不是压缩文件,那么直接读取; 如果是压缩文件,那么解压之后再读取7. 为了保证数据处理的完整性,除了第一个MapTask以外,其他的MapTask都需要从当前切片 的第二行开始,处理到下一个切片的第一行;第一个MapTask要多处理一行;最后一个MapTask会少处理一行数据
- 实际过程中,如果给定的数据和MapReduce提供的输入格式不匹配,那么此时可以考虑自定义输 入格式。考虑到文件还需要进行切片,所以可以定义一个类继承 FileInputFormat ,此时只需要 考虑怎么读取数据即可
- 多源输入:在MapReduce中,如果需要同时处理多个文件,且多个文件位于多个位置,那么此时 需要使用多源输入 1. 在多源输入中,输入的文件格式不可以不同,可以给每一个文件单独指定一个InputFormat2. 在多源输入中,如果输出格式不同,或者Mapper逻辑不同,那么此时可以给每一个文件单独 指定一个Mapper输出格式-OutputFormat
- OutputFormat 发生在Reducer之后,负责将ReduceTask产生的数据按照指定格式写出到指定位 置
- 作用 1. 校验输出路径,主要是确定输出路径要不存在!!!2. 提供输出流将数据写出到指定位置
- 默认情况下,MapReduce中使用的输出格式是 TextOutputFormat , TextOutputFormat 继承了 FileOutputFormat 。需要注意的是, FileOutputFormat 负责校验路径,TextOutputFormat 负责写出数据
- TextOutputFormat 写出数据过程中需要注意的问题: 1. 写出的时候,会先判断是否要对结果进行压缩2. 获取键值对之间的间隔符号,默认是 \t 。可以通过mapreduce.output.textoutputformat.separator 来指定3. 如果对输出结果进行压缩,那么如果没有指定压缩编码,默认会压缩成 .deflate 包4. 如果需要对输出结果进行压缩,那么需要在入口类中添加
- 实际过程中,如果需要指定特殊的输出格式,那么就需要自定义输出格式。需要定义一个类继承 OutputFormat ,但是考虑到还需要校验输出路径是否存在,所以一般是继承 FileOutputFormat
- 扩展:多源输出。将数据根据分类,将结果输出到不同的文件中。案例:字符统计。将字母、数字和符号分别放到不同的文件中进行统计单例模式
- 单例模式(Singleton)是设计模式中最常见、最简单的模式之一 ,属于构建/建造型模式
- 设计模式(design pattern):针对软件开发过程中的某一类问题形成的方案。到目前为止,在软件 开发过程中,有上百种设计模式,其中比较常用的有24种
- 单例模式,顾名思义,指的是在全局只存在唯一的一个实例对象
- 单例模式有六种实现方式:饿汉式、懒汉式、单重所、双重锁(DCL)、枚举式、内部类式 1. 饿汉式
public class A {
// 在类中准备好一个对象,希望所有的使用者都只用准备号的唯一对象
// 饿汉式:在定义对象的时候就初始化对象
// 缺点:无论是否需要使用这个对象,在第一次调用这个类的时候都会初始化这个对象,从
而增长了类的加载时间
// 优点:没有线程的并发问题 - 类只加载一次,所以静态对象也只初始化一次
private static final A a = new A();
// 不允许在类外随便创建对象 - 构造函数私有化
private A(){}
public static A get(){return a;}}
2. 懒汉式
public class A {
// 懒汉式:在定义对象的时候不初始化对象,而是在第一次调用方法的时候再初始化这个对
象
// 优点:在有需要的时候才会初始化对象,从而缩短了类的加载时间
// 缺点:会产生线程的并发问题
private static A a;
private A(){}
public static A get(){
if(a == null) a = new A();return a;}}
3. 单重锁
public class A {
private static A a;
private A(){}
public static A get(){
// 优点:保证线程的并发安全
// 缺点:锁本质上就是保证线程的"独占",因此加锁和解锁都需要消耗资源
// 当对象被初始化之后,后续的所有的线程都需要先加锁,然后判断是否为空,再解
锁,也就意味着所有的线程都需要经历锁的过程
synchronized(A.class){
if(a == null) a = new A();}return a;}}
4. 双重锁(DCL - Double Check Lock)
public class A {
private static A a;
private A(){}
public static A get(){
if(a == null){
synchronized(A.class){
if(a == null){
synchronized(A.class){
a = new A();}}}}return a;}}
5. 枚举式
enum A{
a
}
6. 内部类式
public class A {
public static class AI{
private static final AI instance = new AI();}
public static AI getInstance(){return AI.instance;}}
本文转载自: https://blog.csdn.net/weixin_52442022/article/details/138582279
版权归原作者 百闻,不如一见 所有, 如有侵权,请联系我们删除。
版权归原作者 百闻,不如一见 所有, 如有侵权,请联系我们删除。