Hadoop的I/O操作——序列化(一)

Hadoop的I/O操作——序列化(一)

1. 序列化

(1)基本定义
序列化指的是将结构化的对象转化为字节流,以便在网络上进行传输,或是写入磁盘里进行永久存储;反序列化则是将字节流转回结构化对象。

(2)应用领域
序列化主要用于分布式数据处理的两大领域:进程间通信永久存储(即数据的持久化)。

(3)RPC序列化机制特点
Hadoop利用了RPC来实现进程间的通讯,RPC的序列化机制有以下特点:
1)紧凑
紧凑格式能充分利用网络带宽(数据中心最稀缺的资源),加快传输速度。
2)快速
能减少序列化和反序列化的开销。
3)可扩展
可以随时增加方法调用的新参数。
4)支持互操作
客户端和服务器端可以用不同的语言来实现。

2. Writable接口

2.1 接口介绍

org.apache.hadoop.io.Writable接口是Hadoop序列化机制的核心,该接口定义了两个方法:

package org.apache.hadoop.io;
import java.io.DataOutput; //二进制输出流
import java.io.DataInput; //二进制输入流
import java.io.IOException;

public interface Writable {
	//将对象序列化到二进制输出流
	void write(DataOutput out) throws IOException;
	//从二进制输入流将对象反序列化
	void readFields(DataInput in) throws IOException;
}

Hadoop中有很多类对Writable接口进行了实现,例如IntWritable类,它是对Java数据类型int的包装类。实例化一个IntWritable对象的方法如下:

//法一:
IntWritable writable = new IntWritable();
writable.set(1);
//法二:
IntWritable writable = new IntWritable(1);

2.2 实例1

实现目标
实现一个方法serialize,将一个IntWritable的序列化格式展现出来。

实现过程:
(1)编写MyWritable.java:

import java.io.*;

import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.*;

public class MyWritable {
	public static byte[] serialize(Writable writable) throws IOException {
	/*
	在这个方法中,数据的流向是:writable.write 到 DataOutputStream 到 ByteArrayOutputStream
	*/
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		DataOutputStream dataout = new DataOutputStream(out);
		writable.write(dataout);
		dataout.close();
		return out.toByteArray();
	}

	public static void main(String[] args) throws Exception{
		IntWritable w1 = new IntWritable(5);
		byte[] b1 = serialize(w1);
		System.out.println(StringUtils.byteToHexString(b1));
		
	}
}

(2)编译后利用hadoop命令运行该类:

root@6b08ff31fc7f:/hadoop/hadoop-2.9.1/test/hadoop-io# hadoop MyWritable
00000005

2.3 实例2

实现目标
实现一个方法deserialize,将一个IntWritable的反序列结果展现出来。

实现过程:
(1)编写MyWritable.java:

import java.io.*;

import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.*;

public class MyWritable {
	public static byte[] serialize(Writable writable) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		DataOutputStream dataout = new DataOutputStream(out);
		writable.write(dataout);
		dataout.close();
		return out.toByteArray();
	}

	public static void deserialize(byte[] bytes, Writable writable) throws IOException {
		/*
			此方法中的数据流向是:byte[] 到 ByteArrayInputStream 到 DataInputStream 到 writable.readFields 到 writable
		*/
		ByteArrayInputStream in = new ByteArrayInputStream(bytes);
		DataInputStream datain = new DataInputStream(in);
		writable.readFields(datain); /*writable将datain输入的字节流反序列化为writable对象*/
		datain.close();
		in.close();
	}

	public static void main(String[] args) throws Exception{
		IntWritable w1 = new IntWritable(5);
		byte[] b1 = serialize(w1);
		System.out.println(StringUtils.byteToHexString(b1));
		
		IntWritable w2 = new IntWritable(); /*此时w2里没有值*/
		deserialize(b1, w2);
		System.out.println(w2.get()); /*获取反序列后的对象值*/
	}
}

(2)编译后利用hadoop命令运行该类:

root@6b08ff31fc7f:/hadoop/hadoop-2.9.1/test/hadoop-io# hadoop MyWritable
00000005
5

3. WritableComparable和WritableComparator

对于MapReduce来说,类型的比较很重要,因为中间有个基于键的排序阶段。Java里提供了ComparableComparator两种接口,Hadoop中也提供了对应的接口和类,并且是继承自Java提供的接口的,下面就分别来进行介绍。

3.1 Comparable

(1)java.lang.Comparable接口

在Java里,任何需要进行比较的类型都必须实现java.lang.Comparable接口:

package java.lang;
public interface Comparable<T> {
	public int compareTo(T o);
}

举个实际的例子,class Hellow实现了Comparable接口,并且重写compareTo函数:

package come.test.one;

public class Hellow implements Comparable{
	int i;
	
	public Hellow(int j) {
		i = j;
	}

	@Override
	public int compareTo(Object o) {
		// TODO Auto-generated method stub
		Hellow temp = (Hellow)o;
		if(i == temp.i) {
			return 0;
		}
		else if(i > temp.i) {
			return 1;
		}
		else {
			return -1;
		}
	}	
}

用class hehe中的main函数测试:

package come.test.one;

public class hehe {
	public static void main(String[] args) {
		Hellow h1 = new Hellow(1);
		Hellow h2 = new Hellow(-6);
		int k = h1.compareTo(h2);
		System.out.print(k);
		//输出的k为1
	}
}
(2)org.apache.hadoop.io. WritableComparable接口

在Hadoop中,org.apache.hadoop.io. WritableComparable接口是一个很重要的接口,它继承自org.apache.hadoop.io. Writable接口和java.lang.Comparable接口:

package org.apache.hadoop.io;
public Interface WritableComparable<T> extends Writable,Comparable<T> {
}

3.2 Comparator

(1)java.lang.Comparator接口

在Java中定义了java.util.Comparator接口,这是一个比较器接口,用于比较两个对象:

package java.util;
public interface Comparator<T> {
	int compare(T o1, T o2);
}

举个实际的例子,class Hellow实现了Comparator接口,并且重写compare函数:

package come.test.one;

import java.util.Comparator;

public class Hellow implements Comparator{
	int i;
	
	public Hellow(int j) {
		i = j;
	}

	@Override
	public int compare(Object arg0, Object arg1) {
		// TODO Auto-generated method stub
		Hellow h1 = (Hellow)arg0;
		Hellow h2 = (Hellow)arg1;
		if(h1.i == h2.i) {
			return 0;
		}
		else if(h1.i > h2.i) {
			return 1;
		}
		else {
			return -1;
		}
	}

	
}

类hehe对其进行测试:

package come.test.one;

public class hehe {
	public static void main(String[] args) {
		Hellow h1 = new Hellow(1);
		Hellow h2 = new Hellow(-6);
		Hellow h3 = new Hellow(2);
		int i = h3.compare(h1, h2);
		System.out.println(i);
		//输出为1
	}
}
(2)org.apache.hadoop.io. RawComparator接口

Hadoop提供了一个org.apache.hadoop.io. RawComparator接口,它继承自java.lang.Comparator接口,且该接口还在Comparator接口的基础上新添了一个接口方法:

package org.apache.hadoop.io;
import java.util.Comparator;
public Interface RawComparator<T> extends Comparator<T> {
//新添加的接口方法
	public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2)
}

RawComparator接口定义的这个compare方法可以直接在字节流这一级别进行比较,而不需要将字节流反序列化为对象再进行比较,因此它的效率要高很多。

(3)org.apache.hadoop.io. WritableComparator类

WritableComparator类实现了RawComparator接口,可以用来比较WritableComparable对象,下面举个例子。
A. 编写MyWritable_1.java:

import java.io.*;

import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.*;


public class MyWritable_1 {
	public static byte[] serialize(Writable writable) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		DataOutputStream dataout = new DataOutputStream(out);
		writable.write(dataout);
		dataout.close();
		return out.toByteArray();
	}

	public static void main(String[] args) throws Exception{
		WritableComparator comparator = WritableComparator.get(IntWritable.class);
		IntWritable w1 = new IntWritable(5);
		IntWritable w2 = new IntWritable(10);
		/*此处调用的是Java API的comparator接口方法,在对象级进行比较*/
		int i = comparator.compare(w1, w2); 
		System.out.println("i is " + i);
		//ouput is -1

		byte[] bytes_1 = serialize(w1);
		byte[] bytes_2 = serialize(w2);
		/*此处调用的是HadoopD RawComparator的comparator接口方法,在字节流级别进行比较*/
		int j = comparator.compare(bytes_1, 0, bytes_1.length, bytes_2, 0, bytes_2.length);
		System.out.println("j is " + j);

	}
}

B. 用hadoop命令运行该类:

root@6b08ff31fc7f:/hadoop/hadoop-2.9.1/test/hadoop-io# hadoop MyWritable_1 
i is -1
j is -1

可以看到,两种比较的结果是一样的。

3.3 总结

这些接口和类,可以用UML图来展示它们之间的关系:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值