Hadoop Serialization -- hadoop序列化具体解释 (2)【Text,BytesWritable,NullWritable】

回想:
回想序列化,事实上原书的结构非常清晰,我截图给出书中的章节结构:
序列化最基本的,最底层的是实现writable接口,wiritable规定读和写的游戏规则 (void write(DataOutput out) throws IOException;  void readFields(DataInput in) throws IOException;)。为了适应hadoop的mapreduce的运算特性,也就是map 和reduce对key的比較,排序的功能,就要实现Comparable接口,这个接口规定 public int compareTo(T o);这种方法。为了增强处理大数据集的能力。我们不能老是先序列化,传输,反序列化。然后进行比較compare,太消耗时间和性能了。我们有了增强的RawComparator,RawComparator是Comparator的增强版,能够比較没有被反序列化的数据。

hadoop须要处理的数据五花八门,java具有的基本数据类型都有可能在hadoop中出现,hadoop因此包装了java的基本数据类型使他们实现以上的接口而且给予实现细节。这些类都实现了WritableComparable接口。插上飞翔的翅膀,能够在不同的hadoop节点之间毫无障碍的传输了。如入无人之境。



既然Text拿出来单独讨论。

自然就要好好研究一下Text的实现细节,对于我们对hadoop的设计细节和思想太重要太重要。


Text是UTF-8字符串的Writable实现。被看做是java String类型的替换。Text 类取代了UTF8 类, UTF8 类不支持编码大于32767 个字节的字符.使用了Java 改进过的UTF-8.Text 使用int 型(使用一个可变长度的编码方案)在字符感编码中存储字节数. 最大值是2 GB 。此外。 Text 使用标准的UTF芯,使其更易于与理解U T F-8 的其它工具协同工作.

为什么是2GB,我预计非常少人会思考这个问题,我们简单计算一下:

利用int存储字节长度,int最大是2^31-1,那么字节最大长度就是2^31-1

Text可以容纳的大小R=(2^31-1)/1024/1024/1024=1.99999999=2GB
因此我们使用他的时候要知道他的大小是有限制的。

因为强调使用标准的UTF8,所以Text 和Java 的String 类之间还是有一些差别的。Text 类的索引位于编码后的字节系列中,而不是字符串中的Unicode 字符.或Java 的char 编码单元{如同String 一样)。举比例如以下:


这方面的差异用中文就非常好的说明这个问题。

 String line = "滚滚长江东逝水";
    System.out.println(line.length());
    Text text = new Text(line);
    System.out.println(text.getLength());
    System.out.println(line.charAt(2));
    System.out.println(text.charAt(2));

输出:
7
21

-1
    String line = "merry christmas";
    System.out.println(line.length());
    Text text = new Text(line);
    System.out.println(text.getLength());
    System.out.println(line.charAt(2));
    System.out.println(text.charAt(2));

输出:
15
15
r
114
能够看出来,他们的索引(Index)是真的不一样。同一个索引值取出来的并非同一个东西。


注意, charAt ( )返回了一个int 类型来表示Unicode 代码点, 而不是像String 变量那样返回一个char 类型。

在開始使用一个以上字节进行编码的字符(比如中文。!

), Text 和String 之间的

差别是非常明显的。

下表展示了Unicode的代码点。


U+0041 代码点相应大写字母A 一直到U+00DFUTF-8都是一个字节编码。剩下的都是两个字节以上。而对于java,最后一行,仅仅有最后一个代码点是两个。其它的都是一个字节的。这点区别非常大。

怕非常多人不懂代码点,我再解释一下:
Unicode 是通用字符编码标准。用于表示文本以供计算机处理。Unicode 提供了一种对多语种文本进行一致编码的方法,便于国际文本文件的交换。每一个 Unicode 字符均映射到一个代码点,代码点是一个介于 0 和 1,114,111 之间的整数。Unicode 代码点使用 U+nnnn 形式的表示法来表示(当中 nnnn 是代码点的十六进制数),或使用描写叙述代码点的文本字符串来表示。比如,小写字母 “a” 能够用 U+0061 或文本字符串 "LATIN SMALL LETTER A" 来表示。 代码点能够使用不同的字符编码方案进行编码。

在 Oracle Solaris Unicode 语言环境中,使用的是 UTF-8 形式。UTF-8 是 Unicode 的一种可变长度编码形式,它透明地保留了 ASCII 字符代码值(请參见UTF-8 概述)。 代码点就是一个字符在Unicode中相应的编码。



String 的长度是它包含的字符个数 。但Text 对象的长度是其UTF -8 编码的字节数. 相同。 indexOf () 方泣返回一个char 类型的编码单元的索引。find () 方格是字节偏移量.请看样例:


@Test
public void string() throws UnsupportedEncodingException {
String s = "\u0041\u00DF\u6771\uD801\uDC00";
assertThat(s.length(), is(5));
assertThat(s.getBytes("UTF-8").length, is(10));
assertThat(s.indexOf("\u0041"), is(0));
assertThat(s.indexOf("\u00DF"), is(1));
assertThat(s.indexOf("\u6771"), is(2));
assertThat(s.indexOf("\uD801\uDC00"), is(3));
assertThat(s.charAt(0), is('\u0041'));
assertThat(s.charAt(1), is('\u00DF'));
assertThat(s.charAt(2), is('\u6771'));
assertThat(s.charAt(3), is('\uD801'));
assertThat(s.charAt(4), is('\uDC00'));
assertThat(s.codePointAt(0), is(0x0041));
assertThat(s.codePointAt(1), is(0x00DF));
assertThat(s.codePointAt(2), is(0x6771));
assertThat(s.codePointAt(3), is(0x10400));
}

@Test
public void text() {
Text t = new Text("\u0041\u00DF\u6771\uD801\uDC00");
assertThat(t.getLength(), is(10));   //10 = 1+2+3+4 是其UTF -8 编码的字节数  
assertThat(t.find("\u0041"), is(0));
assertThat(t.find("\u00DF"), is(1));
assertThat(t.find("\u6771"), is(3));
assertThat(t.find("\uD801\uDC00"), is(6));
assertThat(t.charAt(0), is(0x0041));
assertThat(t.charAt(1), is(0x00DF));
assertThat(t.charAt(3), is(0x6771));
assertThat(t.charAt(6), is(0x10400));
}

遍历Text,迭代
迭代使用索引的字节偏移对Text 中的Unicode 字符进行途代是非常复杂的,由于你不能仅仅添加索引。迭代的定义有点模糊(见例4-6 ) 将Text 对象变成java.nio.ByteBuffer然后对缓冲的Text 重复调用bytesToCodePoint() 静态方法.这个方泣提取下一个代码点作为int 然后更新缓冲中的位置。当bytesToCodePoint() 返回- 1 时,检測到字符结束。意思就是说,我们取字符的时候。是一整个一整个字符的取,我们不可以依照索引来取,我们依照代码点整个整个的取。



public class TextIterator {
public static void main(String[] args) {
    Text t = new Text("\u0041\u00DF\u6771\uD801\uDC00");
    ByteBuffer buf = ByteBuffer.wrap(t.getBytes(), 0, t.getLength());
    int cp;
    while (buf.hasRemaining() && (cp = Text.bytesToCodePoint(buf)) != -1) {
    System.out.println(Integer.toHexString(cp));
}
}
}
输出:
41
df
6771
10400

可改动性
String 和Text 的还有一个差别在于可改动性(像Hadoop 中的全部Writable 实视一样。但NullWritable 除外,后者是单实例对象)。

我们能够通过

对它调用set() 函数来重用Text 实例。

示比例如以下:

Text t = new Text("hadoop");
t.set("pig");
assertThat(t.getLength(), is(3));
assertThat(t.getBytes().length, is(3));

转为字符串
Text 不像java. l ang.String 一样有一个能够处理字符串的API ,所以在很多情况下,须要将Text 对象转化为String 对象。这通经常使用toString()方法来完毕。

assertThat(new Text("hadoop ") . toString() , is( "hadoop"));


BytesWritable

BytesWritable 是一个二进制数据数组封装。

它的序列化格式是一个int 字段(4字节) ,指定的是字节数及字节本身。

比如。 一个长度为2 ,值为3 和5 的字节数

组序列化为一个4 字节的整数(00000002)加上两个来自数组的字节(03 和05) 。

BytesWritable b = new BytesWritable(new byte[] { 3, 5 });
byte[] bytes = serialize(b);
assertThat(StringUtils.byteToHexString(bytes), is("000000020305"));

BytesWritab1e 是可变的。其值可通过调用set ( )方撞来改变。和Text一样 。从getBytes ( )方法返回的字节数组大小可能并没有反映出存储在BytesWritable 的数据的实际大小.能够通过调用getLength () 方法来确定BytesWritable 的长度。比如:

b.setCapacity(11);
assertThat(b.getLength(), is(2));
assertThat(b.getBytes().length, is(11));

NullWritable
NullWritable 是一种特殊的Writable 类型,由于它的序列化是零长度的。

没有字节被写入流或从流中读出.它被用作占位符.比如,在MapReduce 中,在不需要这个位置的时候,键或值能够被声明为NullWritable,他有效存储了一个不变的空值。NullWritable 也能够非常实用,在打算存储一系列值的时候,作为SequenceFile 的一个键,而不是键/值对。

它是一个不变的单实例,事实上例能够通

过调用NullWritable.get() 方法来检索。

今天就到这里。

Charles 2015-12-24晚于P.P




版权说明:
本文由Charles Dong原创,本人支持开源以及免费故意的传播。反对商业化谋利。
CSDN博客:http://blog.csdn.net/mrcharles
个人站:http://blog.xingbod.cn
EMAIL:charles@xingbod.cn


转载于:https://www.cnblogs.com/gccbuaa/p/7055880.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370273.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我需要多少个线程?

这取决于您的应用程序。 但是对于那些希望对如何从生产站点购买的所有昂贵内核中挤出更多资金的人来说,请多多包涵,我将阐明围绕多线程 Java应用程序的奥秘。 内容针对最典型的Java EE应用程序进行了“优化”,该应用程序具有Web前端&#xff…

H5网页适配 iPhoneX,就是这么简单

iPhoneX 取消了物理按键,改成底部小黑条,这一改动导致网页出现了比较尴尬的屏幕适配问题。对于网页而言,顶部(刘海部位)的适配问题浏览器已经做了处理,所以我们只需要关注底部与小黑条的适配问题即可&#…

数字校园-云资源平台 2014.10.26-人人通共享空间

近期,教育部在统计学校信息化建设情况,当中一项重要内容,作为三通两平台的一个环节,就是学校开通人人通空间的情况,网上普及了一下知识,不就是十多年前就玩的学校博客的变种吗,网上有一些产品,也是没有热闹起来,为要求而要求的多,既然要求,就来一个吧,花了几天时间,也做了一个.…

Lucene –快速添加索引和搜索功能

什么是Lucene? Apache LuceneTM是完全用Java编写的高性能,功能齐全的文本搜索引擎库。 它是一项适用于几乎所有需要全文搜索的应用程序的技术,尤其是跨平台的应用程序。 Lucene可以纯文本,整数,索引PDF,Of…

《深入理解Java虚拟机》读书笔记3--垃圾回收算法

转载:http://blog.csdn.net/tjiyu/article/details/53983064 下面先来了解Java虚拟机垃圾回收的几种常见算法:标记-清除算法、复制算法、标记-整理算法、分代收集算法、火车算法,介绍它们的算法思路,有什么优点和缺点,…

Flex布局(一)flex-direction

采用Flex布局的元素,被称为Flex容器(flex container),简称"容器"。其所有子元素自动成为容器成员,成为Flex项目(Flex item),简称"项目" Flex-direction调整主轴方向(默认为水平方向)包…

登录网页后要弹出一个新标签_连永久链接都不会,还做什么新媒体?

上次给主编大大发的预览链接失效了,被骂得狗血淋头。大部分运营人可能都遇到过这种情况,忽视了预览生成的链接只是临时的,在12小时后或超过500阅读量后就会失效。一个疏忽,给自己带来了不必要的麻烦,耽误工作&#xff…

static_cast与dynamic_cast转换

static_cast与dynamic_cast转换   一 C语言中存在着两种类型转换: 隐式转换和显式转换 隐式转换:不同数据类型之间赋值和运算,函数调用传递参数……编译器完成 char ch;int i ch; 显示转换:在类型前增加 :&#xff…

vue使用iview Timeline 时间轴不显示问题

vue Timeline 时间轴不显示渲染的效果 官网代码 <Timeline pending><TimelineItem>发布1.0版本</TimelineItem><TimelineItem>发布2.0版本</TimelineItem><TimelineItem>发布3.0版本</TimelineItem><TimelineItem><a href…

Java EE 6 Web配置文件。 在云上。 简单。

Java SE还可以。 Java EE是邪恶的。 这就是我一直想的。 好吧&#xff0c;现在不再了。 让我分享我的经验。 几周前&#xff0c;我开始考虑将旧版spring hibernate tomcat应用程序移植到新平台上&#xff1a; SAP NetWeaver云 。 我知道您在极客那里的想法&#xff1a;…

Kubernetes核心概念总结

1、基础架构 1.1 Master Master节点上面主要由四个模块组成&#xff1a;APIServer、scheduler、controller manager、etcd。 APIServer。APIServer负责对外提供RESTful的Kubernetes API服务&#xff0c;它是系统管理指令的统一入口&#xff0c;任何对资源进行增删改查的操作都要…

php连接mysql数据,php连接mysql数据库

$sql_link mysql_connect("主机名","登入用户名","登入用户名密码");如果连接成功&#xff0c;就会返回一个mysql句柄,可以简单的理解成这个$sql_link 是php跟mysql的一个桥梁&#xff0c;通过该桥梁我们可以进入到mysql。进入到mysql之后&…

url存在宽字节跨站漏洞_利用WebSocket跨站劫持(CSWH)漏洞接管帐户

在一次漏洞悬赏活动中&#xff0c;我发现了一个使用WebSocket连接的应用&#xff0c;所以我检查了WebSocket URL&#xff0c;发现它很容易受到CSWH的攻击(WebSocket跨站劫持)有关CSWH的更多详细信息&#xff0c;可以访问以下链接了解https://www.christian-schneider.net/Cross…

php 数组对比 unset,如何区分PHP中unset,array_splice的区别

1.使用的函数a.函数unset()unset ( mixed $var , mixed $... ? ) : voidunset()销毁指定的变量。b.函数array_slice()array_splice(array,start,length,array)array表示数组。start表示删除元素的开始位置。length表示被移除的元素个数&#xff0c;也是被返回数组的长度。(可…

前端基础-CSS的各种选择器的特点以及CSS的三大特性

一、 基本选择器二、 后代选择器、子元素选择器三、 兄弟选择器四、 交集选择器与并集选择器五、 序列选择器六、 属性选择器七、 伪类选择器八、 伪元素选择器九、 CSS三大特性 一、 基本选择器 1、id选择器 #1、作用&#xff1a;根据指定的id名称&#xff0c;在当前界面中找…

使用JavaCV进行手和手指检测

这篇文章是Andrew Davison博士发布的有关自然用户界面&#xff08;NUI&#xff09;系列的一部分&#xff0c;内容涉及使用JavaCV从网络摄像头视频提要中检测手。 注意&#xff1a;可以从http://fivedots.coe.psu.ac.th/~ad/jg/nui055/下载本章的所有源代码。 第5章的彩色斑点检…

不能装载文档控件。请在检查浏览器的选项中检查浏览器的安全设置_【2020年网络安全宣传周】如何正确设置浏览器...

李夏是一个公司的职员&#xff0c;一天晚上加班赶制文档&#xff0c;由于要向客户汇报产品情况&#xff0c;需要获取大量网上信息&#xff0c;然而在制作中却发现浏览器的网页打不开了。第二天原计划向客户展示的材料未能完整汇总&#xff0c;客户见面对接效果也打了折扣。在当…

用装饰器设计模式装饰

装饰图案是广泛使用的结构图案之一。 此模式在运行时动态更改对象的功能&#xff0c;而不会影响对象的现有功能。 简而言之&#xff0c;此模式通过包装将附加功能添加到对象。 问题陈述&#xff1a; 想像一下我们有一个比萨饼&#xff0c;该比萨饼已经用番茄和奶酪烤制的情况。…

vcpkg安装_微软牌包管理器vcpkg更新及路线图计划

蝎子vcpkg是一套跨平台&#xff0c;开源的C/C库管理器&#xff0c;今天的这篇文章是有关vcpkg主题的2020年4月博文更新。在这篇文章中&#xff0c;我们将分享有关vcpkg 2020.04发布版本的一些信息以及vcpkg的路线图(roadmap)&#xff0c;我们会在这里持续地发布有关vcpkg的最新…

CSS 盒模型与box-sizing

一、盒模型 一个web页面由许多html元素组成&#xff0c;而每一个html元素都可以表示为一个矩形的盒子&#xff0c;CSS盒模型正是描述这些矩形盒子的存在。 MDN的描述&#xff1a; When laying out a document, the browsers rendering engine represents each element as a r…