Hadoop序列化中的Writable接口(附部分源码)

Hadoop序列化中的Writable接口(附部分源码)

序列化是将结构化对象为字节流以便与通过网络进行传输或者写入持久存储。反序列化指的是将字节流转为一系列结构化对象的过程。

序化在分布式数据处理的两大领域经常出现:进程间通信和永久存储

hadoop中,节点直接的进程间通信是用远程过程调用(RPC)实现的。RPC协议将消息序列化成二进制流后发送到运城节点,远程节点接着将二进制流反序列化为原始的消息。

在Hadoop中,Writable接口定义了两个方法:一个用于将其状态写入二进制格式的DataOutput流,另一个用于从二进制格式的DataInput流读取其态。

packageorg.apache.hadoop.io; importjava.io.DataOutput; importjava.io.DataInput; importjava.io.IOException; public interface Writable { void write(DataOutput out)throws IOException; void readFields(DataInput in)throws IOException;

write和readFields分别实现了把对象序列化和反序列化的功能

让我们来看一个特别的Writable,看看可以对它进行哪些操作。我们要使用IntWritable,这是一个Java的int对象的封装。可以使用set()函数来创建和设置它的值:

IntWritable writable =new IntWritable(); writable.set(163);

类似地,我们也可以使用构造函数:

IntWritable writable =newIntWritable(163);

为了检查IntWritable的序列化形式,我们写一个小的辅助方法,它把一个java.io.ByteArrayOutputStream封装到java.io.DataOutputStream中(java.io.DataOutput的一个实现),以此来捕获序列化的数据流中的字节:

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

整数用四个字节写入(我们使用JUnit 4断言):

byte[] bytes = serialize(writable); assertThat(bytes.length, is(4));

字节使用大端顺序写入(所以,最重要的字节写在数据流的开始处,这是由java.io.DataOutput接口规定的),我们可以使用Hadoop的StringUtils方法看到它们的十六进制表示:

assertThat(StringUtils.byteToHexString(bytes), is("000000a3"));

让我们再来试试反序列化。我们创建一个帮助方法来从一个字节数组读取一个Writable对象:

public static byte[] deserialize(Writable writable,byte[] bytes) throws IOException { ByteArrayInputStream in =new ByteArrayInputStream(bytes); DataInputStream dataIn =new DataInputStream(in); writable.readFields(dataIn); dataIn.close(); return bytes; }

我们构造一个新的、缺值的IntWritable,然后调用deserialize()方法来读取刚写入的输出流。然后发现它的值(使用get方法检索得到)还是原来的值163:

IntWritable newWritable =new IntWritable(); deserialize(newWritable, bytes); assertThat(newWritable.get(), is(163));

WritableComparable 和comparator

IntWritable实现了WritableComparable接口,后者是Writable和java.lang.Comparable接口的子接口。

packageorg.apache.hadoop.io; public interface WritableComparable<t> extends Writable, Comparable<t> { }

类型的比较对MapReduce而言至关重要的,键和键之间的比较是在排序阶段完成。Hadoop提供的一个优化方法是从Java Comparator的RawComparator扩展

packageorg.apache.hadoop.io; importjava.util.Comparator; public interface RawComparator<t> extends Comparator<t> { public int compare(byte[] b1,ints1,intl1,byte[] b2,ints2,intl2); }
 package java.util; public interface Comparator<T> {     int compare(T o1, T o2);     boolean equals(Object obj); }

这个接口允许执行者比较从流中读取的未被反序列化为对象的记录,从而省去了创建对象的所有开销。例如,IntWritables的comparator使用原始的compare()方法从每个字节数组的指定开始位置(S1和S2)和长度(L1和L2)读取整数b1和b2然后直接进行比较。

WritableComparator是RawComparator对WritableComparable类的一个通用实现。它提供两个主要功能。首先,它提供了一个默认的对原始compare()函数的调用,对从数据流对要比较的对象进行反序列化,然后调用对象的compare()方法其次,它充当的是RawComparator实例的一个工厂方法(Writable方法已经注册)。例如,为获得IntWritable的comparator,我们只需使用:

RawComparator<intwritable> comparator = WritableComparator.get(IntWritable.class);

WritableComparator get方法源码:

private static HashMap<Class, WritableComparator> comparators = new HashMap<Class, WritableComparator>(); // registry /** Get a comparator for a {@link WritableComparable} implementation. */ public static synchronized WritableComparator get(Class<? extends WritableComparable> c) { WritableComparator comparator = comparators.get(c); if (comparator == null) comparator = new WritableComparator(c, true); return comparator; }

comparator可以用来比较两个IntWritable:

IntWritable w1 =newIntWritable(163); IntWritable w2 =newIntWritable(67); assertThat(comparator.compare(w1, w2), greaterThan(0));

或者它们的序列化描述: 

byte[] b1 = serialize(w1); byte[] b2 = serialize(w2); assertThat(comparator.compare(b1, 0, b1.length, b2, 0, b2.length), greaterThan(0));

WritableComparator的compare()方法的源码:

public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) { try { buffer.reset(b1, s1, l1); // parse key1 key1.readFields(buffer); buffer.reset(b2, s2, l2); // parse key2 key2.readFields(buffer); } catch (IOException e) { throw new RuntimeException(e); } return compare(key1, key2); // compare them } @SuppressWarnings("unchecked") public int compare(WritableComparable a, WritableComparable b) { return a.compareTo(b); }

参考:《hadoop权威指南》

转载于:https://my.oschina.net/winHerson/blog/130145

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110135.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux x11vnc,X11vnc (简体中文)[通俗易懂]

    linux x11vnc,X11vnc (简体中文)[通俗易懂]WARNING:这将建立一个没有密码的VNC.意思是任何人都可以通过网络访问你的VNC并且能看到你的X界面.可以非常简单的通过SSH连接来避免这样的事情.设置x11vnc安装pacman-Sx11vnc运行首先你需要运行一个xserver服务器.使用startx或类似的.完成后运行startxx11vnc-display:0-auth~/.Xauthority如果失败,你…

    2025年8月10日
    4
  • 黑盒测试、白盒测试到底差别是什么?

    黑盒测试、白盒测试到底差别是什么?邓小平曾言:不管白猫、黑猫,能抓到老鼠就是好猫。如果用在软件测试领域,这句话也一点都没错。不管黑盒、白盒,能找出Bug、发现缺陷,保证软件质量才是王道。对于刚踏足软件测试的新手小白来说,黑盒测试、

    2022年7月1日
    23
  • Android Layout 之 RelativeLayout RelativeLayout.LayoutParams

    Android Layout 之 RelativeLayout RelativeLayout.LayoutParamsAndroidLayout之RelativeLayout使用AbsoluteLayout可以直接指定其子View的绝对位置,这种布局方式虽然简单,但是不够灵活。比如在一个程序中,按钮2位于按钮1的下方且和按钮1左对齐,我们可以使用指定两个按钮的绝对位置的方式布局,但是当布局完成后,由于某些原因,这两个按钮需要相左平移一些距离以便在父View右边留出一些空白区域…

    2022年7月17日
    16
  • 服务网关配置_服务网关作用

    服务网关配置_服务网关作用目录第一章Gateway介绍1.1、什么是Gateway1.2、为啥用Gateway第二章Gateway三大核心第三章Gateway工作流程第四章Gateway路由功能4.1、项目准备与启动4.2、工程搭建与测试4.3、配置自定义路由4.4、禁止默认的路由4.5、配置动态的路由4.6、用代码来配路由4.7、为下章节做准备第五章Gateway断言功能5.1、谓词:Path5.2、谓词:After5.3、谓词:Before5.4、谓词:Between5.5、谓词:Cookie5.6、谓词:Header

    2022年10月10日
    3
  • Applet 数字签名技术完全攻略

    Applet 数字签名技术完全攻略

    2021年12月17日
    41
  • html一个汉字空格占位_html空格字符

    html一个汉字空格占位_html空格字符1.&nbsp;(常用)不换行空格,全称No-BreakSpace,它是按下space键产生的空格。空格不会累加(只显示一个)。使用html表示才会累加,该空格占据宽度受字体影响。2.&ensp;半角空格,全称EnSpace,en为em宽度的一半(em类似于px受设置不同为20px=1em或其他自定义大小)。占据0.5个中文宽度,不受字体影响。3、&em…

    2022年10月4日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号