MapReduce知识点详解二

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

序列化概念

序列化(Serialization)是指把结构化对象转化为字节流。

反序列化(Deserialization)是序列化的逆过程。即把字节流转回结构化对象。

Java序列化(java.io.Serializabl)

Hadoop序列化的特点

1.紧凑:高效使用存储空间。

2.快速:读写数据的额外开销小

3.可扩展:可透明地读取老格式的数据

4.互操作:支持多语言的交互

Hadoop序列化的作用

序列化在分布式环境的两大作用:进程间通信,永久存储。

Hadoop节点间通信。

MapReduce知识点详解二_第1张图片

自定义Writable类

class KpiWritable  implements Writable{
    int uppacknum;
    int downpacknum;
    int uppayload;
    int downpayload;
    
    public KpiWritable() {
        super();
    }
    
    public void set(String uppacknum, String downpacknum, String uppayload,
            String downpayload) {
        this.uppacknum = Integer.parseInt(uppacknum);
        this.downpacknum = Integer.parseInt(downpacknum);
        this.uppayload = Integer.parseInt(uppayload);
        this.downpayload = Integer.parseInt(downpayload);
    }
    public KpiWritable(int uppacknum, int downpacknum, int uppayload,
            int downpayload) {
        super();
        this.uppacknum = uppacknum;
        this.downpacknum = downpacknum;
        this.uppayload = uppayload;
        this.downpayload = downpayload;
    }
    
    public KpiWritable(String uppacknum, String downpacknum, String uppayload,
            String downpayload) {
        super();
        this.set(uppacknum, downpacknum, uppayload, downpayload);
    }
    @Override
    public void write(DataOutput out) throws IOException {
        out.writeInt(this.uppacknum);
        out.writeInt(this.downpacknum);
        out.writeInt(this.uppayload);
        out.writeInt(this.downpayload);
    }
    @Override
    public void readFields(DataInput in) throws IOException {
        this.uppacknum = in.readInt();
        this.downpacknum = in.readInt();
        this.uppayload = in.readInt();
        this.downpayload = in.readInt();
    }
    
    @Override
    public String toString() {
        return uppacknum +"\t"+ downpacknum +"\t"+uppayload +"\t"+downpayload;
    }
}

Writable

   1.write 是把每个对象序列化到输出流

   2.readFields是把输入流字节反序列化

实现WritableComparable.

Java值对象的比较:一般需要重写toString(),hashCode(),equals()方法

基于文件的存储结构

SequenceFile 无序存储

MapFile 会对key建立索引文件,value按key顺序存储

基于MapFile的结构有:

ArrayFile 像我们使用的数组一样,key值为序列化的数字

SetFile 他只有key,value为不可变的数据

BloomMapFile 在 MapFile 的基础上增加了一个 /bloom 文件,包含的是二进制的过滤表,在每一次写操作完成时,会更新这个过滤表。

SequenceFile

SequeceFile是Hadoop API提供的一种二进制文件支持。这种二进制文件直接将对序列化到文件中。一般对小文件可以使用这种文件合并,即将文件名作为key,文件内容作为value序列化到大文件中。这种文件格式有以下好处:

支持压缩,且可定制为基于Record或Block压缩(Block级压缩性能较优)

本地化任务支持:因为文件可以被切分,因此MapReduce任务时数据的本地化情况应该是非常好的。

对key、value的长度进行了定义,(反)序列化速度非常快。

缺点是需要一个合并文件的过程,文件较大,且合并后的文件将不方便查看,必须通过遍历查看每一个小文件。

MapReduce知识点详解二_第2张图片

public static void main(String[] args) throws Exception{
        final Configuration conf = new Configuration();
        final FileSystem fs = FileSystem.get(new URI("hdfs://hadoop:9000/"), conf);
        //写操作
        final Writer writer = new SequenceFile.Writer(fs, conf, new Path("/sf"), LongWritable.class, Text.class);
        writer.append(new LongWritable(1), new Text("111"));
        IOUtils.closeStream(writer);
        //读操作
        final SequenceFile.Reader reader = new SequenceFile.Reader(fs, new Path("/sf"), conf);
        final LongWritable key = new LongWritable();
        final Text val = new Text();
        while (reader.next(key, val)) {
            System.out.println(key.get()+"\t"+val.toString());
        }
        IOUtils.closeStream(reader);
    }

MapFile

MapFile是排序后的SequenceFile,通过观察其目录结构可以看到MapFile由两部分组成,分别是data和index。

index作为文件的数据索引,主要记录了每个Record的key值,以及该Record在文件中的偏移位置。在MapFile被访问的时候,索引文件会被加载到内存,通过索引映射关系可迅速定位到指定Record所在文件位置,因此,相对SequenceFile而言,MapFile的检索效率是高效的,缺点是会消耗一部分内存来存储index数据。

需注意的是,MapFile并不会把所有Record都记录到index中去,默认情况下每隔128条记录存储一个索引映射。当然,记录间隔可人为修改,通过MapFIle.Writer的setIndexInterval()方法,或修改io.map.index.interval属性;

另外,与SequenceFile不同的是,MapFile的KeyClass一定要实现WritableComparable接口,即Key值是可比较的。

public static void main(String[] args) throws Exception{
        final Configuration conf = new Configuration();
        final FileSystem fs = FileSystem.get(new URI("hdfs://hadoop:9000/"), conf);
        //写数据
        final MapFile.Writer writer = new MapFile.Writer(conf, fs, "/aaa", Text.class, Text.class);
        writer.append(new Text("1"), new Text("aa"));
        IOUtils.closeStream(writer);
        //读数据
        final MapFile.Reader reader = new MapFile.Reader(fs, "/aaa", conf);
        final Text key = new Text();
        final Text val = new Text();
        while(reader.next(key, val)) {
            System.out.println(key.toString()+"\t"+val.toString());
        }
}

MapReduce知识点详解二_第3张图片

小文件存储

注意:使用MapFile或SequenceFile虽然可以解决HDFS中小文件的存储问题,但也有一定局限性,如:

1.文件不支持复写操作,不能向已存在的SequenceFile(MapFile)追加存储记录

2.当write流不关闭的时候,没有办法构造read流。也就是在执行文件写操作的时候,该文件是不可读取的

MapReduce输入的处理类

FileInputFormat:

FileInputFormat是所有以文件作为数据源的InputFormat实现的基类,

FileInputFormat保存作为job输入的所有文件,并实现了对输入文件计算splits的方法。至于获得记录的方法是有不同的子类——TextInputFormat进行实现的。

InputFormat

MapReduce知识点详解二_第4张图片

InputFormat 负责处理MR的输入部分.

有三个作用:

验证作业的输入是否规范.

把输入文件切分成InputSplit.

提供RecordReader 的实现类,把InputSplit读到Mapper中进行处理.

InputSplit

◆   在执行mapreduce之前,原始数据被分割成若干split,每个split作为一个map任务的输入,在map执行过程中split会被分解成一个个记录(key-value对),map会依次处理每一个记录。

◆   FileInputFormat只划分比HDFS block大的文件,所以FileInputFormat划分的结果是这个文件或者是这个文件中的一部分.               

◆   如果一个文件的大小比block小,将不会被划分,这也是Hadoop处理大文件的效率要比处理很多小文件的效率高的原因。

◆    当Hadoop处理很多小文件(文件大小小于hdfs block大小)的时候,由于FileInputFormat不会对小文件进行划分,所以每一个小文件都会被当做一个split并分配一个map任务,导致效率底下。

 例如:一个1G的文件,会被划分成16个64MB的split,并分配16个map任务处理,而10000个100kb的文件会被10000个map任务处理。  

TextInputFormat

◆  TextInputformat是默认的处理类,处理普通文本文件。

◆  文件中每一行作为一个记录,他将每一行在文件中的起始偏移量作为key,每一行的内容作为value。

◆  默认以\n或回车键作为一行记录。

◆  TextInputFormat继承了FileInputFormat。

底层架构

MapReduce知识点详解二_第5张图片

其他输入类

◆    CombineFileInputFormat

         相对于大量的小文件来说,hadoop更合适处理少量的大文件。

         CombineFileInputFormat可以缓解这个问题,它是针对小文件而设计的。

◆    KeyValueTextInputFormat

         当输入数据的每一行是两列,并用tab分离的形式的时候,KeyValueTextInputformat处理这种格式的文件非常适合。

◆    NLineInputformat 
         NLineInputformat可以控制在每个split中数据的行数。

◆    SequenceFileInputformat 

         当输入文件格式是sequencefile的时候,要使用SequenceFileInputformat作为输入。

Hadoop的输出处理类

TextOutputformat

       默认的输出格式,key和value中间值用tab隔开的。

◆    SequenceFileOutputformat

       将key和value以sequencefile格式输出。

◆    SequenceFileAsOutputFormat

       将key和value以原始二进制的格式输出。

◆    MapFileOutputFormat

       将key和value写入MapFile中。由于MapFile中的key是有序的,所以写入的时候必须保证记录是按key值顺序写入的。

◆    MultipleOutputFormat

        默认情况下一个reducer会产生一个输出,但是有些时候我们想一个reducer产生多个输出,MultipleOutputFormat和MultipleOutputs可以实现这个功能。


转载于:https://my.oschina.net/yangzhiyuan/blog/266399

你可能感兴趣的:(MapReduce知识点详解二)