1.定制Writable类型

Hadoop中有一套Writable实现,例如:IntWritable、Text等,但是,有时候可能并不能满足自己的需求,这个时候,就需要自己定制Writable类型。

定制分以下几步:

  • 需要实现WritableComparable接口,因为Writable常常作为健值对出现,而在MapReduce中,中间有个排序很重要,因此,Hadoop中就让Writable实现了WritableComparable
  • 需要实现WritableComparable的write()、readFields()、compareTo()方法
  • 需要重写java.lang.Object中的hashCode()、equals()、toString()方法。

由于hashCode()方法对reduce分区很重要,所以,需要重写java.lang.Object的hashCode()方法

如果要结合使用TextOutputFormat和定制的Writable,则许重写java.lang.Object的toString()方法

Example:

CreateWritable.java

 package cn.roboson.writable;

 import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException; import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
/**
* 1.定制一个Writable类型,里面包含两个Text
* 2.和IntWritable等原有的Writable类似,它需要实现WritableComparable
* 3.由于hashCode()方法对reduce分区很重要,所以,需要重写java.lang.Object的hashCode()方法
* 4.如果要结合使用TextOutputFormat和定制的Writable,则许重写java.lang.Object的toString()方法
* @author roboson
*
*/ public class CreateWritable implements WritableComparable<CreateWritable>{ private Text first;
private Text second; //构造方法,这个是必须要的
public CreateWritable(){ } public CreateWritable(String first,String second){
set(new Text(first), new Text(second));
} public CreateWritable(Text first,Text second){
set(first,second);
} public Text getFirst() {
return first;
} public void setFirst(Text first) {
this.first = first;
} public Text getSecond() {
return second;
} public void setSecond(Text second) {
this.second = second;
} public void set(Text first,Text second){
this.first=first;
this.second=second;
} @Override
public void readFields(DataInput in) throws IOException {
// TODO Auto-generated method stub
first.readFields(in);
second.readFields(in);
} @Override
public void write(DataOutput out) throws IOException {
// TODO Auto-generated method stub
first.write(out);
second.write(out);
} @Override
public int compareTo(CreateWritable other) {
// TODO Auto-generated method stub
int cmp=first.compareTo(other.getFirst());
if(cmp!=0){
return cmp;
}
return second.compareTo(other.getSecond());
} @Override
public int hashCode() {
// TODO Auto-generated method stub
return first.hashCode()*163 + second.hashCode();
} @Override
public String toString() {
// TODO Auto-generated method stub
return first+"\t"+second;
} @Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj instanceof CreateWritable){
CreateWritable create = (CreateWritable) obj;
return first.equals(create.getFirst()) && second.equals(create.getSecond());
}
return false;
} }

Writable06.java

 package cn.roboson.writable;

 import org.apache.hadoop.io.Text;

 public class Writable06 {

     public static void main(String[] args) {
CreateWritable createWritable01 = new CreateWritable("Hadoop", "roboson");
CreateWritable createWritable02 = new CreateWritable(new Text("Hadoop"), new Text("roboson")); //重写了equals()方法,相比叫first 和 second两者都相同的时候,返回true
System.out.println(createWritable01.equals(createWritable02)); //重写了compareTo()方法,先比较first,再比较second,返回0:相等 -1:first<second 1:first>second
System.out.println(createWritable01.compareTo(createWritable02)); //重写了toString()方法,返回 first +"\t"+second
System.out.println(createWritable01.toString());
}
}

运行结果:

2.为速度实现一个RawComparator

关于Comparator方面的知识,可以参考我的博文《Hadoop中WritableComparable 和 comparator》,Comparator中,有一个方法是compare(byte[] b1,int s1,int l1,byte[] b2,int s2, int l2),该方法直接比较的是序列化,不必先将序列化数据流转化为对象,再进行比较,所以,与上面的compareTo()方法,相比,其更高效!其实,我们查看HadoopAPI,就可以发现,基本类型的Writable类都实现有了Comparator作为其内部类:

好,再看看IntWritable.Comparator这个类,如下图所示,发现它是一个静态类,好好观察它的结构:

通过上面的,我们可以发现,要为一个Writable实现一个Comparator,安装Hadoop的格式来,需要注意以下几点:

  • 将其在内部实现,作为内部类
  • 是一个静态的内部类
  • 注册,以便可以通过WritableComparator直接创建

至于注册方面的知识,可以查看我的博客《Hadoop中Comparator原理

Example:给上面自定义的CreateWritable类实现一个Comparator,也就是CreateWritable.Comparator类

CreateWritable.java

 package cn.roboson.writable;

 import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Comparator; import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.io.WritableUtils;
/**
* 1.给定制的CreateWritable类实现一个Comparator,CreateWritable.Comparator
* @author roboson
*
*/ public class CreateWritable implements WritableComparable<CreateWritable>{ private Text first;
private Text second; //构造方法,这个是必须要的
public CreateWritable(){ } public CreateWritable(String first,String second){
set(new Text(first), new Text(second));
} public CreateWritable(Text first,Text second){
set(first,second);
} public Text getFirst() {
return first;
} public void setFirst(Text first) {
this.first = first;
} public Text getSecond() {
return second;
} public void setSecond(Text second) {
this.second = second;
} public void set(Text first,Text second){
this.first=first;
this.second=second;
} @Override
public void readFields(DataInput in) throws IOException {
// TODO Auto-generated method stub
first.readFields(in);
second.readFields(in);
} @Override
public void write(DataOutput out) throws IOException {
// TODO Auto-generated method stub
System.out.println(first);
first.write(out);
second.write(out);
} @Override
public int compareTo(CreateWritable other) {
// TODO Auto-generated method stub
int cmp=first.compareTo(other.getFirst());
if(cmp!=0){
return cmp;
}
return second.compareTo(other.getSecond());
} @Override
public int hashCode() {
// TODO Auto-generated method stub
return first.hashCode()*163 + second.hashCode();
} @Override
public String toString() {
// TODO Auto-generated method stub
return first+"\t"+second;
} @Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj instanceof CreateWritable){
CreateWritable create = (CreateWritable) obj;
return first.equals(create.getFirst()) && second.equals(create.getSecond());
}
return false;
} //创建静态内部类:CreateWritable.Comparator
public static class Comparator extends WritableComparator{ public Comparator() {
super(CreateWritable.class);
// TODO Auto-generated constructor stub
}
private static final Text.Comparator TEXT_COMPARATOR = new Text.Comparator(); @Override
public int compare(byte[] b1, int s1, int l1, byte[] b2,
int s2, int l2) {
// TODO Auto-generated method stub
int firstL1 = 0,firstL2 = 0;
try {
firstL1 = WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1, s1);
firstL2 = WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2, s2);
int cmp = TEXT_COMPARATOR.compare(b1, s1, firstL1, b2, s2, firstL2);
if(cmp !=0){
return cmp;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return TEXT_COMPARATOR.compare(b1, s1+firstL1, l1-firstL1, b2, s2+firstL2, l2-firstL2);
} }
static{
WritableComparator.define(CreateWritable.class,new Comparator());
}
}

Writable07.java

 package cn.roboson.writable;

 import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException; import org.apache.hadoop.io.RawComparator;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparator; public class Writable07 { public static void main(String[] args) throws IOException { CreateWritable create01 = new CreateWritable(new Text("Hadoop"), new Text("1"));
CreateWritable create02 = new CreateWritable(new Text("Hadoop"), new Text("2"));
byte[] b1 = serialize(create01);
byte[] b2 = serialize(create02);
RawComparator<CreateWritable> comparator = WritableComparator.get(CreateWritable.class);
int cmp =comparator.compare(b1, 0, b1.length, b2, 0, b2.length);
if(cmp ==0){
System.out.println("create01 == create02");
}else if(cmp ==-1){
System.out.println("create01<create02");
}else{
System.out.println("create01>create02");
}
} public static byte[] serialize(Writable writable) throws IOException{
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(out);
writable.write(dataOut);
return out.toByteArray(); }
}

运行结果:

分析:

在上面的CreateWritable的内部类Comparator中,需要实现一个方法compare()方法,那么compare该如何实现,才能够对序列化数据流进行比较。

CreateWritable是由两个Text对象组成的(Text first, Text second),而Text对象的二进制表示,是一个长度可变的整数,包含字符串之UTF-8表示的字节数以及UTF-8字节本身。诀窍在于读取该对象的起始长度,由此得知第一个Text对象的字节表示有多长;然后将该长度传递给Text对象的RawComparator方法,最后通过计算第一个字符串和第二个字符串恰当的偏移量,这样便可以实现对象的比较。

也就是说Text对象序列化后,也是由两部分组成,一部分是记录本身有多少个字节,另一部分就是它自己的字节数!

记录它本身有多少个字节所占用的字节长度:WritableUtils.decodeVintSize()方法返回一个整数,代表它的字节长度。

它自己本身的字节数:WritableComparator的readVInt()方法返回一个整数,代表它本身的字节长度。

这样就方便了,相比叫first的序列化数据流,根据结果,判断,看是否需要再比较second的序列化数据流。

Hadoop中Writable类之四的更多相关文章

  1. Hadoop中Writable类之三

    1.BytesWritable <1>定义 ByteWritable是对二进制数据组的封装.它的序列化格式为一个用于指定后面数据字节数的整数域(4个字节),后跟字节本身. 举个例子,假如有 ...

  2. Hadoop中Writable类之二

    1.ASCII.Unicode.UFT-8 在看Text类型的时候,里面出现了上面三种编码,先看看这三种编码: ASCII是基于拉丁字母的一套电脑编码系统.它主要用于显示现代英语和其他西欧语言.它是现 ...

  3. Hadoop中Writable类

    1.Writable简单介绍 在前面的博客中,经常出现IntWritable,ByteWritable.....光从字面上,就可以看出,给人的感觉是基本数据类型 和 序列化!在Hadoop中自带的or ...

  4. hadoop中Text类 与 java中String类的区别

    hadoop 中 的Text类与java中的String类感觉上用法是相似的,但两者在编码格式和访问方式上还是有些差别的,要说明这个问题,首先得了解几个概念: 字符集: 是一个系统支持的所有抽象字符的 ...

  5. hadoop中典型Writable类详解

    本文地址:http://www.cnblogs.com/archimedes/p/hadoop-writable.html,转载请注明源地址. Hadoop将很多Writable类归入org.apac ...

  6. hadoop中实现定制Writable类

    Hadoop中有一套Writable实现可以满足大部分需求,但是在有些情况下,我们需要根据自己的需要构造一个新的实现,有了定制的Writable,我们就可以完全控制二进制表示和排序顺序. 为了演示如何 ...

  7. hadoop中的序列化与Writable类

    本文地址:http://www.cnblogs.com/archimedes/p/hadoop-writable-class.html,转载请注明源地址. hadoop中自带的org.apache.h ...

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

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

  9. Hadoop中序列化与Writable接口

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

随机推荐

  1. Hive之 hive-1.2.1 + hadoop 2.7.4 集群安装

    一. 相关概念 Hive Metastore有三种配置方式,分别是: Embedded Metastore Database (Derby) 内嵌模式Local Metastore Server 本地 ...

  2. Ubuntu各种indicator汇总

    1.  indicator-multiload: 可视化图形显示 sudo apt-get install indicator-multiload 2. indicator-sysmonitor: 以 ...

  3. c# .net 编程方式修改环境变量无效的解决办法

    无论是修改注册表方式(System\ControlSet001\Control\Session Manager\Environment"),还是用Environment.SetEnviron ...

  4. 老叶观点:MySQL开发规范之我见(更新版)

    转自:http://mp.weixin.qq.com/s?__biz=MjM5NzAzMTY4NQ==&mid=207239419&idx=2&sn=bddbe0a657758 ...

  5. 虚拟机Linux桥接模式下设置静态IP

    之前一直使用NAT模式,测试时android端远程访问虚拟机的mysql时发现无法连接,但是访问同学拷过来的虚拟机Linux的mysql却成功了,想了下原因是他设置的桥接模式.关于两种模式的区别,网上 ...

  6. 【转】Java 字节流与字符流的区别

    字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢?实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作 ...

  7. QT win 安装配置

    QT windows 版安装配置 安装包:链接:https://pan.baidu.com/s/1LCj2V3xQ1wB9_7zmE5tV6Q 密码:bn9r 首先安装QT Creator 双击安装文 ...

  8. 走迷宫(用队列bfs并输出走的路径)

    #include <iostream> #include <stack> #include <string.h> #include <stdio.h> ...

  9. Golang后台开发初体验

    转自:http://blog.csdn.net/cszhouwei/article/details/37740277 补充反馈 slice 既然聊到slice,就不得不提它的近亲array,这里不太想 ...

  10. 前端基础——AJAX

    一  简介 AJAX(Asynchronous Javascript And XML),即AJAX = 异步JavaScript + XML.AJAX是一种用于创建快速动态网页的技术. AJAX两大特 ...