回顾:
回顾序列化,其实原书的结构很清晰,我截图给出书中的章节结构:
序列化最主要的,最底层的是实现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));
输出:
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));
}
}
}
输出:
可修改性
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
- Hadoop Hive sql语法详解
Hadoop Hive sql语法详解 Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构 化的数据文件 ...
- hadoop应用开发技术详解
<大 数据技术丛书:Hadoop应用开发技术详解>共12章.第1-2章详细地介绍了Hadoop的生态系统.关键技术以及安装和配置:第3章是 MapReduce的使用入门,让读者了解整个开发 ...
- 《Hadoop应用开发技术详解》
<Hadoop应用开发技术详解> 基本信息 作者: 刘刚 丛书名: 大数据技术丛书 出版社:机械工业出版社 ISBN:9787111452447 上架时间:2014-1-10 出版日期:2 ...
- Hadoop生态圈-Kafka配置文件详解
Hadoop生态圈-Kafka配置文件详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.默认kafka配置文件内容([yinzhengjie@s101 ~]$ more /s ...
- Hadoop基础-Idea打包详解之手动添加依赖(SequenceFile的压缩编解码器案例)
Hadoop基础-Idea打包详解之手动添加依赖(SequenceFile的压缩编解码器案例) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.编辑配置文件(pml.xml)(我 ...
- Hadoop MapReduce执行过程详解(带hadoop例子)
https://my.oschina.net/itblog/blog/275294 摘要: 本文通过一个例子,详细介绍Hadoop 的 MapReduce过程. 分析MapReduce执行过程 Map ...
- 【大数据】Linux下安装Hadoop(2.7.1)详解及WordCount运行
一.引言 在完成了Storm的环境配置之后,想着鼓捣一下Hadoop的安装,网上面的教程好多,但是没有一个特别切合的,所以在安装的过程中还是遇到了很多的麻烦,并且最后不断的查阅资料,终于解决了问题,感 ...
- hadoop之hdfs命令详解
本篇主要对hadoop命令和hdfs命令进行阐述,yarn命令会在之后的文章中体现 hadoop fs命令可以用于其他文件系统,不止是hdfs文件系统内,也就是说该命令的使用范围更广可以用于HDFS. ...
- hadoop之hdfs架构详解
本文主要从两个方面对hdfs进行阐述,第一就是hdfs的整个架构以及组成,第二就是hdfs文件的读写流程. 一.HDFS概述 标题中提到hdfs(Hadoop Distribute File Syst ...
- Hadoop伪分布安装详解(三)
目录: 1.修改主机名和用户名 2.配置静态IP地址 3.配置SSH无密码连接 4.安装JDK1.7 5.配置Hadoop 6.安装Mysql 7.安装Hive 8.安装Hbase 9.安装Sqoop ...
随机推荐
- New Concept English three (39)
26w/m 70errors The rough across the plain soon became so bad that we tried to get Bruce to drive bac ...
- 通过TortoiseSVN checkout的文件前面没有“状态标识”
问题描述:安装完成VisualSVN Server.VisualSVn和TortoiseSVN后,然后通过SVN Server新建Repository(仓库),用Visual Studio新建一个So ...
- SVN的搭建及使用(三)用TortoiseSVN修改文件,添加文件,删除文件,以及如何解决冲突,重新设置用户名和密码等
添加文件 在检出的工作副本中添加一个Readme.txt文本文件,这时候这个文本文件会显示为没有版本控制的状态,如图: 这时候,你需要告知TortoiseSVN你的操作,如图: 加入以后,你的文件会变 ...
- Android Issue分析方法(用anr来说明)
Log的产生大家都知道 , 大家也都知道通过DDMS来看log , 但什么时候会产生log文件呢 ?一般在如下几种情况会产生log文件 . 1,程序异常退出 , uncaused exception ...
- Unity 2D 入门
原文:Introduction to Unity 2D 作者:Sean Duffy 译者:kmyhy 3/15/17 更新说明: 升级至 Unity 5.5. Unity 是一个非常流行和强大的游戏引 ...
- FFmpeg再学习 -- 视音频基础知识
最近一直在看雷霄骅 FFmpeg 系列视频,然后将自己的理解总结一下. 参看:<基于 FFmpeg + SDL 的视频播放器的制作>课程的视频 一.视频播放器原理 自己理解: 比如一个 M ...
- (九)jsMath
1.Math对象 作用:用于执行数学任务,把Math作为对象就可以调用其方法和属性. eg: typeof Math); 2.Math属性 PI:圆周率(约等于 3.1415926); ...
- phpcms URL修改
修改caches\configs\system.php中'html_root' => 'html',//生成静态文件路径改成'html_root' => '',//生成静态文件路径,然后修 ...
- vs中删除nuget包
最近发现有些解决方案都是用来nuget包,这个偶尔能跑,但是有一个爱抽风的毛病,生成解决方案的时候报错:无法连接到远程服务器,真几把蛋疼.... 就是下图的情况 网上找了下不是很容易找到处理这个问题的 ...
- 【知识笔记】前端样式CSS
一.页脚如何始终固定在页面底部显示 想要达到页脚固定在页面底部显示,也就是当页面主体高度在浏览器高度范围内时页脚靠浏览器底部,超出浏览器高度时页脚在页面主体下方,相当于在高度上的自适应. 乍看似乎很简 ...