Hadoop序列化与Writable接口(一)

序列化

序列化(serialization)是指将结构化的对象转化为字节流,以便在网络上传输或者写入到硬盘进行永久存储;相对的反序列化(deserialization)是指将字节流转回到结构化对象的过程。

在分布式系统中进程将对象序列化为字节流,通过网络传输到另一进程,另一进程接收到字节流,通过反序列化转回到结构化对象,以达到进程间通信。在Hadoop中,Mapper,Combiner,Reducer等阶段之间的通信都需要使用序列化与反序列化技术。举例来说,Mapper产生的中间结果(<key: value1, value2...>)需要写入到本地硬盘,这是序列化过程(将结构化对象转化为字节流,并写入硬盘),而Reducer阶段读取Mapper的中间结果的过程则是一个反序列化过程(读取硬盘上存储的字节流文件,并转回为结构化对象),需要注意的是,能够在网络上传输的只能是字节流,Mapper的中间结果在不同主机间洗牌时,对象将经历序列化和反序列化两个过程。

序列化是Hadoop核心的一部分,在Hadoop中,位于org.apache.hadoop.io包中的Writable接口是Hadoop序列化格式的实现。

Writable接口

Hadoop Writable接口是基于DataInput和DataOutput实现的序列化协议,紧凑(高效使用存储空间),快速(读写数据、序列化与反序列化的开销小)。Hadoop中的键(key)和值(value)必须是实现了Writable接口的对象(键还必须实现WritableComparable,以便进行排序)。

以下是Hadoop(使用的是Hadoop 1.1.2)中Writable接口的声明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package org.apache.hadoop.io;

import java.io.DataOutput;
import java.io.DataInput;
import java.io.IOException; public interface Writable {
/**
* Serialize the fields of this object to <code>out</code>.
*
* @param out <code>DataOuput</code> to serialize this object into.
* @throws IOException
*/
void write(DataOutput out) throws IOException; /**
* Deserialize the fields of this object from <code>in</code>.
*
* <p>For efficiency, implementations should attempt to re-use storage in the
* existing object where possible.</p>
*
* @param in <code>DataInput</code> to deseriablize this object from.
* @throws IOException
*/
void readFields(DataInput in) throws IOException;
}

Writable类

Hadoop自身提供了多种具体的Writable类,包含了常见的Java基本类型(boolean、byte、short、int、float、long和double等)和集合类型(BytesWritable、ArrayWritable和MapWritable等)。这些类型都位于org.apache.hadoop.io包中。

(图片来源:safaribooksonline.com)

定制Writable类

虽然Hadoop内建了多种Writable类提供用户选择,Hadoop对Java基本类型的包装Writable类实现的RawComparable接口,使得这些对象不需要反序列化过程,便可以在字节流层面进行排序,从而大大缩短了比较的时间开销,但是当我们需要更加复杂的对象时,Hadoop的内建Writable类就不能满足我们的需求了(需要注意的是Hadoop提供的Writable集合类型并没有实现RawComparable接口,因此也不满足我们的需要),这时我们就需要定制自己的Writable类,特别将其作为键(key)的时候更应该如此,以求达到更高效的存储和快速的比较。

下面的实例展示了如何定制一个Writable类,一个定制的Writable类首先必须实现Writable或者WritableComparable接口,然后为定制的Writable类编写write(DataOutput out)和readFields(DataInput in)方法,来控制定制的Writable类如何转化为字节流(write方法)和如何从字节流转回为Writable对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package com.yoyzhou.weibo;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.VLongWritable;
import org.apache.hadoop.io.Writable; /**
*This MyWritable class demonstrates how to write a custom Writable class
*
**/
public class MyWritable implements Writable{ private VLongWritable field1;
private VLongWritable field2; public MyWritable(){
this.set(new VLongWritable(), new VLongWritable());
} public MyWritable(VLongWritable fld1, VLongWritable fld2){ this.set(fld1, fld2); } public void set(VLongWritable fld1, VLongWritable fld2){
//make sure the smaller field is always put as field1
if(fld1.get() <= fld2.get()){
this.field1 = fld1;
this.field2 = fld2;
}else{ this.field1 = fld2;
this.field2 = fld1;
}
} //How to write and read MyWritable fields from DataOutput and DataInput stream
@Override
public void write(DataOutput out) throws IOException { field1.write(out);
field2.write(out);
} @Override
public void readFields(DataInput in) throws IOException { field1.readFields(in);
field2.readFields(in);
} /** Returns true if <code>o</code> is a MyWritable with the same values. */
@Override
public boolean equals(Object o) {
if (!(o instanceof MyWritable))
return false; MyWritable other = (MyWritable)o;
return field1.equals(other.field1) && field2.equals(other.field2); } @Override
public int hashCode(){ return field1.hashCode() * 163 + field2.hashCode();
} @Override
public String toString() {
return field1.toString() + "\t" + field2.toString();
} }

未完待续,下一篇中将介绍Writable对象序列化为字节流时占用的字节长度以及其字节序列的构成。

参考资料

Tom White, Hadoop: The Definitive Guide, 3rd Edition

---To Be Continued---

Hadoop序列化与Writable接口(一)的更多相关文章

  1. Hadoop序列化与Writable接口(二)

    Hadoop序列化与Writable接口(二) 上一篇文章Hadoop序列化与Writable接口(一)介绍了Hadoop序列化,Hadoop Writable接口以及如何定制自己的Writable类 ...

  2. Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable

    酒,是个好东西,前提要适量.今天参加了公司的年会,主题就是吃.喝.吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个喷子!在大家推杯换盏之际,难免一些画面浮现脑 ...

  3. hadoop中的序列化与Writable接口

    本文地址:http://www.cnblogs.com/archimedes/p/hadoop-writable-interface.html,转载请注明源地址. 简介 序列化和反序列化就是结构化对象 ...

  4. Hadoop中序列化与Writable接口

    学习笔记,整理自<Hadoop权威指南 第3版> 一.序列化 序列化:序列化是将 内存 中的结构化数据 转化为 能在网络上传输 或 磁盘中进行永久保存的二进制流的过程:反序列化:序列化的逆 ...

  5. Hadoop序列化

      遗留问题: Hadoop序列化可以复用对象,是在哪里复用的? 介绍Hadoop序列化机制 Hadoop序列化机制详解 Hadoop序列化的核心 Hadoop序列化的比较接口 ObjectWrita ...

  6. Hadoop基础-序列化与反序列化(实现Writable接口)

    Hadoop基础-序列化与反序列化(实现Writable接口) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.序列化简介 1>.什么是序列化 序列化也称串行化,是将结构化 ...

  7. Hadoop Serialization hadoop序列化详解(最新版) (1)【java和hadoop序列化比较和writable接口】

    初学java的人肯定对java序列化记忆犹新.最开始很多人并不会一下子理解序列化的意义所在.这样子是因为很多人还是对java最底层的特性不是特别理解,当你经验丰富,对java理解更加深刻之后,你就会发 ...

  8. 为什么hadoop中用到的序列化不是java的serilaziable接口去序列化而是使用Writable序列化框架

    继上一个模块之后,此次分析的内容是来到了Hadoop IO相关的模块了,IO系统的模块可谓是一个比较大的模块,在Hadoop Common中的io,主要包括2个大的子模块构成,1个是以Writable ...

  9. eclipse 提交作业到JobTracker Hadoop的数据类型要求必须实现Writable接口

    问:在eclipse中的写的代码如何提交作业到JobTracker中的哪?答:(1)在eclipse中调用的job.waitForCompletion(true)实际上执行如下方法 connect() ...

随机推荐

  1. centos7 rabbitmq 安装

    http://www.rabbitmq.com/install-rpm.html Overview rabbitmq-server is included in Fedora. However, th ...

  2. Ubuntu相关命令

    此贴包含自己搭建网站以及自学Ubuntu遇到的相关命令,方便以后查看,故相关帖子整理记录在此! 用户切换 当前用户切换到root用户,只需要执行sudo su即可. root用户切回user用户,只需 ...

  3. 微信小程序获取当前页面的路径的方式

    使用getCurrentPages可以获取当前加载中所有的页面对象的一个数组,数组最后一个就是当前页面. var pages = getCurrentPages() //获取加载的页面 var cur ...

  4. OC-NSArray

    一.认识数组 oc中可以把NSObject对象的子类放到数组这个集合中,但是int.float.double等基础数据类型需要先进行转换才可以存入数组. oc中数组以NS开头,其中分为可变数组和不可变 ...

  5. 《Effective C++》第3章 资源管理(2)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  6. 第6课:datetime模块、操作数据库、__name__、redis、mock接口

    1.  datetime模块 import datetime print(datetime.datetime.today()) # 当前时间 2018-01-23 17:22:35.739667 pr ...

  7. powershell -enc参数无法解码base64编码payload的解决方案

    powershell的-enc参数允许传入一个base64编码过的powershell脚本字符串作为参数来执行该powershell脚本,该方法常被用于绕过杀毒软件的主动防御机制. 今天下午在做一个后 ...

  8. Linux系统下第三方软件安装实例

    在第三方软件安装的时候,首先要有自己的rpm安装包!然后要有可以使用的yum源(前面有关于yum源的介绍) 一.安装wps步骤如下: 1)首先进入安装包所在目录,并查看有没有要安装的软件 2)然后,对 ...

  9. EasyPlayer RTSP Windows(with ActiveX/OCX插件)播放器支持H.265播放与抓图功能

    EasyPlayer作为业界一款比较优秀的RTSP播放器,一直深受用户的好评,经过了近3年的开发和迭代,从一开始的简单PC版本的RTSP播放功能,到如今支持PC(支持ocx插件).Android.iO ...

  10. [Python] 计算dataframe某一文本维度的平均长度

    print np.mean(df.title.apply(lambda x: len(x))) # 24.072694718 print df.title.apply(lambda x: len(x) ...