Hadoop基于DataInput和DataOutput实现了简单、高效的序列化协议,而Writable接口定义了Hadoop序列化的方法,MapReduce框架中的不论什么键值类型都实现了该接口,比方IntWritable、LongWritable等,具体的类关系见下图:

通过上图可以发现,MapReduce中经常使用的键值类型都没有直接实现Writable接口,而是实现了该接口的子接口WritableComparable,该子接口还继承了Comparable接口,这意味着实现类除了可以序列化和发序列化外,还可以彼此进行比較,这是由于当这些类做为键在MapReduce中使用时,在排序阶段须要对其进行比較排序。但这并非说假设实现自己定义的序列化类时,必须实现WritableComparable接口,仅当自己定义的序列化类也用作键时才必须实现该接口,假设仅是做为值使用的话,仅实现Writable接口就可以。

当自己定义的序列化类用做键时,须要考虑到在依据键进行分区时经经常使用到hashCode()方法,因此须要确保该方法在不同的JVM实例中返回同样的结果,而Object对象中默认的hashCode()方法不可以满足该特性,所以在实现自己定义类时须要重写hashCode()方法,而假设两个对象依据equals()方法是相等的,那么二者的hashCode()返回值也必须同样,因此在重写hashCode()的时候,有必要重写equals(Object obj)方法。

除了上图中实现WritableComparable的类外,还有若干类直接实现了Writable接口,比方ObjectWritable,一个多态的Writable,该类不使用Writable封装就行处理数组、字符串和其他Java基本类型。还有Writable集合类:ArrayWritable、EnumSetWritable、MapWritable、TwoDArrayWritable、SortedMapWritable。当中ArrayWritable是对同样Writable类型的数组的封装,也就是该类中Writable的类型必须同样,是IntWritable都是IntWritable,不能既有IntWritable也有LongWritable。TwoDArrayWritable是对二维数组即矩阵的封装,同样该类中Writable的类型也必须同样。EnumSetWritable是对EnumSet封装的Writable,MapWritable实现了Map<Writable,Writable>接口,SortedMapWritable实现了SortedMap<WritableComparable,Writable>接口,二者当然也都实现了Writable接口,在二者的内部实现中,使用Byte类型指示指定的类型,因此在一个Map实例中最多仅仅能有127个不同的类:

/* Class to id mappings */
@VisibleForTesting
Map<Class, Byte> classToIdMap = new ConcurrentHashMap<Class, Byte>();
/* Id to Class mappings */
@VisibleForTesting
Map<Byte, Class> idToClassMap = new ConcurrentHashMap<Byte, Class>();

如今通过分析IntWritable和Text的源码来学习怎样编写Writable以及WritableComparable,首先是IntWritable的源码:

public class IntWritable implements WritableComparable<IntWritable> {
private int value;
public IntWritable() {}
public IntWritable(int value) { set(value); }
/** Set the value of this IntWritable. */
public void set(int value) { this.value = value; }
/** Return the value of this IntWritable. */
public int get() { return value; }
@Override
//重写Writable中的readFields(DataInput in)
public void readFields(DataInput in) throws IOException {
value = in.readInt();
}
@Override
//重写Writable中的write(DataOutput out)
public void write(DataOutput out) throws IOException {
out.writeInt(value);
}
/** Returns true if <code>o</code> is a IntWritable with the same value. */
@Override
public boolean equals(Object o) {
if (!(o instanceof IntWritable))
return false;
IntWritable other = (IntWritable)o;
return this.value == other.value;
}
@Override
public int hashCode() {
return value;
}
/** Compares two IntWritables. */
@Override
//重写Comparable接口中的compareTo方法
public int compareTo(IntWritable o) {
int thisValue = this.value;
int thatValue = o.value;
return (thisValue<thatValue ? -1 : (thisValue==thatValue ? 0 : 1));
}
@Override
public String toString() {
return Integer.toString(value);
}
//此处省略了继承自WritableComparator的内部类Comparator
static { // register this comparator
WritableComparator.define(IntWritable.class, new Comparator());
}
}

IntWritable的源码相对来说还是比較简单的,除了实现接口中的方法外,还重写了hashCode、equals和toString方法,这也是要注意的一点。其次是Text类,Text将字符串存储为标准UTF8编码,提供了在字节层次序列化、反序列化和比較字符串的方法,比方decode(byte[]utf8)、encode(String string)、readFields(DataInput in)、write(DataOutput out)等。该类除了实现WritableComparable外,还继承自BinaryComparable抽象类,当中实现的方法例如以下:

private byte[] bytes;
private int length;
@Override
public void readFields(DataInput in) throws IOException {
//从输入流中读取整数值,很多其他工具方法可參考WritableUtils工具类
int newLength = WritableUtils.readVInt(in);
setCapacity(newLength, false);
//向bytes中读入长度为newLength的数据
in.readFully(bytes, 0, newLength);
length = newLength;
}
@Override
public void write(DataOutput out) throws IOException {
WritableUtils.writeVInt(out, length);
out.write(bytes, 0, length);
}
@Override
public int compareTo(BinaryComparable other) {
if (this == other)
return 0;
return WritableComparator.compareBytes(getBytes(), 0, getLength(),
other.getBytes(), 0, other.getLength());
}

总结IntWritable和Text类的实现,可以据此实现自定的WritableComparable,以下就是一个简单的演示样例。在该演示样例中使用name和age做为联合键,仅仅有在二者都同样的情况下才觉得是一个对象。

public class CompositeWritable implements WritableComparable<CompositeWritable>{
private String name;
private int age;
public CompositeWritable(){}
public CompositeWritable(String name, int age){
set(name, age);
}
@Override
public void readFields(DataInput in) throws IOException {
name = in.readUTF();
age = in.readInt();
}
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(age);
}
@Override
public int compareTo(CompositeWritable o) {
int cmp = name.compareTo(o.getName());
if(cmp != 0)
return cmp;
return age < o.getAge()? -1:(age == o.getAge()? 0 : 1);
}
@Override
public boolean equals(Object o) {
if(o instanceof CompositeWritable){
CompositeWritable other = (CompositeWritable)o;
return this.name.equals(other.name) && this.age == other.age;
}
return false;
}
@Override
public int hashCode() {
return name.hashCode() + age;
}
@Override
public String toString() {
return name + "\t" + age;
}
public void set(String name, int age){
this.name = name;
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}

Hadoop-2.4.1学习之Writable及事实上现的更多相关文章

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

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

  2. 开启Hadoop和Spark的学习之路

    Hadoop Hadoop是一个由Apache基金会所开发的分布式系统基础架构. 用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力进行高速运算和存储. Hadoop实现了一个 ...

  3. Hadoop 2.2.0学习笔记20131210

    伪分布式单节点安装执行pi失败: [root@server- ~]# ./bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples ...

  4. Hadoop 2.2.0学习笔记20131209

    1.下载java 7并安装 [root@server- ~]# rpm -ivh jdk-7u40-linux-x64.rpm Preparing... ####################### ...

  5. hadoop自带TestDFSIO学习

    hadoop系统中,包含了很多测试工具包,如测试mapreduce系统读写文件系统,有testDFSIO工具 首先安装好hadoop,配置好环境变量 进入share目录下的mapreduce目录下面, ...

  6. Hadoop学习---Hadoop的HBase的学习

    Hbase Hbase的特点: Hbase是bigtable的开源的仿制版本 建立在HDFS之上 可靠性,靠性能 大:一个表可以有上亿行,上百万列 面向列:面向列(族)的存储和权限控制,列(族)独立检 ...

  7. MR hadoop streaming job的学习 combiner

    代码已经拷贝到了公司电脑的: /Users/baidu/Documents/Data/Work/Code/Self/hadoop_mr_streaming_jobs 首先是主控脚本 main.sh 调 ...

  8. [Spring Data Repositories]学习笔记--使用现有的repository

    以下内容是在学习Spring-Data-mongoDB中的Spring Data Repositories时做的一些笔记.备忘! 感觉学习还是看官方的资料比较透彻一些. Spring Data Rep ...

  9. [Hadoop] Hadoop学习历程 [持续更新中…]

    1. Hadoop FS Shell Hadoop之所以可以实现分布式计算,主要的原因之一是因为其背后的分布式文件系统(HDFS).所以,对于Hadoop的文件操作需要有一套全新的shell指令来完成 ...

随机推荐

  1. 大约session_cached_cursors在不同的db在默认不同的版本号

    大约session_cached_cursors的值,不同db版本号具有不同的默认值: 9i是 0 10.1 0 10.2 是20 11.1 是50 11.2 是50 12.1 是50 值值得注意的是 ...

  2. 第二章_session管理

    2.1 URL重写 URL重写是Session追踪技术.须要将一个或多个token做为一个查询字符串加入到一个URL中. Token的格式通常是键=值. Url?key-1=value-1&k ...

  3. 腾讯2014在广州站实习生offer经验(TEG-开发背景)

    研究在过去的一年是linux 什么系统编程和网络编程.比较熟悉的语言c/c++,python只写一些测试client.是后台开发类,比方前面笔面的网易CC(面完hr后挂).大概3月15号就在腾讯 jo ...

  4. POJ 2208 已知边四面体六个长度,计算体积

    Pyramids Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2718   Accepted: 886   Special ...

  5. ubuntu,从一个新用户,要转到新用户的命令行操作

    shibo-ubuntu@ubuntu:~$ sudo useradd karen [sudo] password for shibo-ubuntu:  shibo-ubuntu@ubuntu:~$ ...

  6. UVa 10397 Connect the Campus

    最小生成树 Kruskal #include<cmath> #include<iostream> #include<cstdio> #include<algo ...

  7. SQL Server 内存泄露(memory leak)——游标导致的内存问题

    原文:SQL Server 内存泄露(memory leak)--游标导致的内存问题 转自:http://blogs.msdn.com/b/apgcdsd/archive/2011/07/01/sql ...

  8. 装双系统(win7/win8/ubuntu)问题总结

    1.假设你要安装双系统,装系统是最好安装winows,然后再装ubuntu,因此,不解决它自己入选,我一般装ubuntu时刻.第一分区删除.然后用U硬盘直接安装ubuntu.在这一刻ubuntu将投入 ...

  9. SQL入门学习0-数据库与SQL

    1.1 DBMS DatabaseManagermentSystem 数据库管理系统 DBMS种类 层次型数据库(HDB) 最古老的数据库之一,把数据通过层次结构的方式表现. 关系型数据库(RDB) ...

  10. 三种字符编码:ASCII、Unicode和UTF-8

    原文:三种字符编码:ASCII.Unicode和UTF-8 什么是字符编码? 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字 ...