Hadoop-2.4.1学习之Writable及其实现

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;
	}
}
时间: 2024-08-10 15:11:44

Hadoop-2.4.1学习之Writable及其实现的相关文章

Cloudera Spark 及 Hadoop 开发员培训学习【北京上海】

Spark 及 Hadoop 开发员培训 学习如何将数据导入到 Apache Hadoop 机群并使用 Spark.Hive.Flume.Sqoop.Impala 及其他 Hadoop 生态系统工具对数据进行各种操作和处理分析 在为期四天的培训中,学员将学习关键概念和掌握使用最新技术和工具将数据采集到 Hadoop 机群并进行处理.通过学习掌握诸如 Spark.Hive.Flume.Sqoop 和 Impala 这样的 Hadoop 生态系统工具和技术,Hadoop 开发员将具备解决实际大数据问

【hadoop】16、学习hive操作语句

学习DDL语句 创建对象的语句 Create/Drop/Alter Database Create Database CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name [COMMENT database_comment] [LOCATION hdfs_path] [WITH DBPROPERTIES (property_name=property_value, ...)]; Drop Database DROP (DATABASE|SC

【转】hadoop深入研究:(十一)——序列化与Writable实现

原文链接 http://blog.csdn.net/lastsweetop/article/details/9249411 所有源码在github上,https://github.com/lastsweetop/styhadoop 简介 在hadoop中,Writable的实现类是个庞大的家族,我们在这里简单的介绍一下常用来做序列化的一部分. java原生类型 除char类型以外,所有的原生类型都有对应的Writable类,并且通过get和set方法可以他们的值. IntWritable和Lon

Hadoop大数据开发学习路线图阶段一

Hadoop发展到今天家族产品已经非常丰富,能够满足不同场景的大数据处理需求.作为目前主流的大数据处理技术,市场上很多公司的大数据业务都是基于Hadoop开展,而且对很多场景已经具有非常成熟的解决方案. 作为开发人员掌握Hadoop及其生态内框架的开发技术,就是进入大数据领域的必经之路. 下面详细介绍一下,学习Hadoop开发技术的路线图. Hadoop本身是用java开发的,所以对java的支持性非常好,但也可以使用其他语言. 下面的技术路线侧重数据挖掘方向,因为Python开发效率较高所以我

大数据Hadoop核心知识入门学习注意事项

今天来介绍新手学习hadoop的入门注意事项.这篇文章一来谈谈hadoop核心知识学习. 首先hadoop分为hadoop1.X和hadoop2.X,并且还有hadoop生态系统,那么下面我们以hadoop2.x为例进行详细介绍: Hadoop的核心是mapreduce和hdfs. Mapreduce:mapreduce是很多人都需要迈过去的槛,它比较难以理解,我们有时候即使写出了mapreduce程序,但是还是摸不着头脑.我们都知道mapreduce是一种编程模型,那么它能干什么,对我有什么用

2018年最新Hadoop大数据开发学习路线图

Hadoop发展到今天家族产品已经非常丰富,能够满足不同场景的大数据处理需求.作为目前主流的大数据处理技术,市场上很多公司的大数据业务都是基于Hadoop开展,而且对很多场景已经具有非常成熟的解决方案. 作为开发人员掌握Hadoop及其生态内框架的开发技术,就是进入大数据领域的必经之路. 下面详细介绍一下,学习Hadoop开发技术的路线图. Hadoop本身是用java开发的,所以对java的支持性非常好,但也可以使用其他语言. 下面的技术路线侧重数据挖掘方向,因为Python开发效率较高所以我

Spark、Hadoop、Hive安装学习

1.Hive安装 http://blog.csdn.net/an342647823/article/details/46048403 2.Hadoop安装 http://www.itnose.net/detail/6182168.html 3.Spark安装 http://stark-summer.iteye.com/blog/2173219 http://ju.outofmemory.cn/entry/177769

hadoop官方文档学习笔记(1)——resource manager HA

resource manager HA是hadoop自从2.4之后推出的功能,以Active/Standby的方式提供冗余,目的是为了消除单点失败的风险. 1.总体架构: 2.故障切换:有自动和手动两种形式. 手动:如果以手动形式切换,使用yarn haadmin命令首先将Active节点转为standby,再将standby节点转为active. 自动:RM有基于zookeeper的节点选举机制决定哪一个是活动节点.不需要像HDFS一样部署一个zkfc守护进程,因为RM内嵌了这样的功能. 做了

hadoop Java API、 hadoop Streaming 、hadoop Pipes 三者比较学习

1.hadoop  Java  API Hadoop的主要编程语言是Java,因而,Java API是最基本的对外编程接口. 2. hadoop    Streaming             1.概述 它是为方便非java用户编写Mapreduce程序而设计的工具包. Hadoop Streaming是Hadoop提供的一个编程工具,它允许用户使用任何可执行文件或者脚本文件作为Mapper和Reducer, 例如: 采用shell脚本语言中的一些命令作为mapper和reducer(cat作