回顾:
回顾序列化,其实原书的结构很清晰,我截图给出书中的章节结构:
序列化最主要的,最底层的是实现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


Hadoop Serialization -- hadoop序列化详解 (2)的更多相关文章

  1. Hadoop Hive sql语法详解

    Hadoop Hive sql语法详解 Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构 化的数据文件 ...

  2. hadoop应用开发技术详解

    <大 数据技术丛书:Hadoop应用开发技术详解>共12章.第1-2章详细地介绍了Hadoop的生态系统.关键技术以及安装和配置:第3章是 MapReduce的使用入门,让读者了解整个开发 ...

  3. 《Hadoop应用开发技术详解》

    <Hadoop应用开发技术详解> 基本信息 作者: 刘刚 丛书名: 大数据技术丛书 出版社:机械工业出版社 ISBN:9787111452447 上架时间:2014-1-10 出版日期:2 ...

  4. Hadoop生态圈-Kafka配置文件详解

    Hadoop生态圈-Kafka配置文件详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.默认kafka配置文件内容([yinzhengjie@s101 ~]$ more /s ...

  5. Hadoop基础-Idea打包详解之手动添加依赖(SequenceFile的压缩编解码器案例)

    Hadoop基础-Idea打包详解之手动添加依赖(SequenceFile的压缩编解码器案例) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.编辑配置文件(pml.xml)(我 ...

  6. Hadoop MapReduce执行过程详解(带hadoop例子)

    https://my.oschina.net/itblog/blog/275294 摘要: 本文通过一个例子,详细介绍Hadoop 的 MapReduce过程. 分析MapReduce执行过程 Map ...

  7. 【大数据】Linux下安装Hadoop(2.7.1)详解及WordCount运行

    一.引言 在完成了Storm的环境配置之后,想着鼓捣一下Hadoop的安装,网上面的教程好多,但是没有一个特别切合的,所以在安装的过程中还是遇到了很多的麻烦,并且最后不断的查阅资料,终于解决了问题,感 ...

  8. hadoop之hdfs命令详解

    本篇主要对hadoop命令和hdfs命令进行阐述,yarn命令会在之后的文章中体现 hadoop fs命令可以用于其他文件系统,不止是hdfs文件系统内,也就是说该命令的使用范围更广可以用于HDFS. ...

  9. hadoop之hdfs架构详解

    本文主要从两个方面对hdfs进行阐述,第一就是hdfs的整个架构以及组成,第二就是hdfs文件的读写流程. 一.HDFS概述 标题中提到hdfs(Hadoop Distribute File Syst ...

  10. Hadoop伪分布安装详解(三)

    目录: 1.修改主机名和用户名 2.配置静态IP地址 3.配置SSH无密码连接 4.安装JDK1.7 5.配置Hadoop 6.安装Mysql 7.安装Hive 8.安装Hbase 9.安装Sqoop ...

随机推荐

  1. Elasticsearch Painless语言(实现搜索打分基础)

    With the release of Elasticsearch 5.x came Painless, Elasticsearch's answer to safe, secure, and per ...

  2. ndoutils_mq项目: 发送Nagios的性能、报警、配置文件到RabbitMQ

    本人目前开发的一个项目,改造ndoutils,主要是它的ndomod. 将性能.报警.配置文件使用JSON格式发送到RabbitMQ. 由于NEB(Nagios Event Broker)使用C开发, ...

  3. Leetcode 890. Find and Replace Pattern

    把pattern映射到数字,也就是把pattern标准化. 比如abb和cdd如果都能标准化为011,那么就是同构的. class Solution: def findAndReplacePatter ...

  4. (二)java环境搭建

    Java运行环境的搭建: 什么是JRE,什么是JDK? JRE:(java运行环境)包括jvm(java虚拟机)和java运行的核心类库,如果只是运行java程序,只需安装JRE JDK:(java开 ...

  5. 2017 山东二轮集训 Day7 国王

    2017 山东二轮集训 Day7 国王 题目大意 给定一棵树,每个点有黑白两种颜色,定义一条简单路径合法当且仅当路径上所有点黑色与白色数量相等,求有多少非空区间 \([L,R]\) ,使得所有编号 \ ...

  6. 剑指offer-第六章面试中的各项能力(不用加减乘除做加法)

    //不用加减乘除四则运算,来做加法 //题目:两个数做加法. //思路:用二进制的位运算的思路.第一步:首先两数相加考虑进位.可以用异或. //第二步:两个数相加只考虑进位,并将最后的结果左移.第三步 ...

  7. 【BZOJ2850】巧克力王国 KDtree

    [BZOJ2850]巧克力王国 Description 巧克力王国里的巧克力都是由牛奶和可可做成的.但是并不是每一块巧克力都受王国人民的欢迎,因为大家都不喜 欢过于甜的巧克力.对于每一块巧克力,我们设 ...

  8. c#学习笔记 VS编辑器常用设置

    1.NET Framework 4.0安装好后目录在哪里? C:\Windows\Microsoft.NET\Framework下面 C#中CLR和IL分别是什么含义? CLR common lang ...

  9. Ambari的资源池管理

    操作: YARN→Config→Advanced→Schedule capacity-scheduler=null yarn.scheduler.capacity.default.minimum-us ...

  10. php无wsdl webservice服务用法

    服务端: <?php class test { function add($a,$b) { return $a+$b; } } function getUserInfo($name) { ret ...