学习笔记,整理自《Hadoop权威指南 第3版》

一、序列化

  序列化:序列化是将 内存 中的结构化数据 转化为 能在网络上传输 或 磁盘中进行永久保存的二进制流的过程;反序列化:序列化的逆过程;

  应用:进程间通信、网络传输、持久化;

  Hadoop中是使用的自己的序列化格式Writable,以及结合用Avro弥补一些Writable的不足;

二:Writable接口 相关:

  主要是3个接口:

    Writable接口

    WritableComparable接口  

    RawComparator接口

Writable接口中主要是两个方法:write 和 readFields

  1. //Writable接口原形
  2. public interface Writabel{
  3. void write(DataOutput out)throws IOException;
  4. void readFields(DataInput in) throws IOException;
  5. }

WritableComparable接口:继承自Writable接口 和 Comparable<T>接口;即有序列功能,也有比较排序功能; 

  1. public interface WritableComparable<T> extends Writable,Comparable<T>{
  2. }

Hadoop自定义比较排序接口:RawComparator接口,该接口允许实现比较数据流中的记录,而不用把数据流反序列化为对象,从而避免了新建对象的额外开销;

  可参考:Hadoop-2.4.1学习之RawComparator及其实现

  1. public interface RawComparator<T> extends Comparator<T>{
  2. public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2);
  3. }

工具类WritableComparator:a. 充当RawComparator的实例工厂;b. 提供了对原始compare()方法的一个默认实现;

  1. RawComparator<IntWritable> comparator = WritableComparator.get(IntWritable.class);
  2.  
  3. //获取的comparator 即可比较两个IntWritable对象,也可直接比较两个序列化数据:
  4.  
  5. //比较两上IntWritable对象
  6. IntWritable w1 = new IntWritable(163);
  7. IntWritable w2 = new IntWritable(67):
  8. comparator.compare(w1, w2);
  9.  
  10. //比较其序列化
  11. byte[] b1 = serialize(w1);
  12. byte[] b2 = serialize(w2);
  13. comparator.compare(b1, 0, b1.length, b2, 0, b2.length);

三、Writable继承图

  以上可以看出,包含了除了char类型外 Java基本类型的封装;其中Text对应Java中的String;

四、自定义一个Writable

  1. import java.io.DataInput;
  2. import java.io.DataOutput;
  3. import java.io.IOException;
  4.  
  5. import org.apache.hadoop.io.Text;
  6. import org.apache.hadoop.io.WritableComparable;
  7.  
  8. public class TextPair implements WritableComparable<TextPair> {
  9. private Text first;
  10. private Text second;
  11.  
  12. public TextPair() {
  13. set(new Text(), new Text());
  14. }
  15.  
  16. public void set(Text first, Text second) {
  17. this.first = first;
  18. this.second = second;
  19. }
  20.  
  21. public Text getFirst() {
  22. return this.first;
  23. }
  24.  
  25. public Text getSecond() {
  26. return this.second;
  27. }
  28.  
  29. @Override
  30. public void write(DataOutput out) throws IOException {
  31. first.write(out);
  32. second.write(out);
  33. }
  34.  
  35. @Override
  36. public void readFields(DataInput in) throws IOException {
  37. first.readFields(in);
  38. second.readFields(in);
  39. }
  40.  
  41. @Override
  42. public int hashCode() {
  43. return first.hashCode() * 163 + second.hashCode();
  44. }
  45.  
  46. @Override
  47. public boolean equals(Object o) {
  48. if (this == o)
  49. return true;
  50.  
  51. if (o instanceof TextPair) {
  52. TextPair tp = (TextPair) o;
  53. return first.equals(tp.first) && second.equals(tp.second);
  54. }
  55. return false;
  56. }
  57.  
  58. @Override
  59. public int compareTo(TextPair tp) {
  60. int cmp = first.compareTo(tp.first);
  61. if (cmp != 0) {
  62. return cmp;
  63. }
  64. return second.compareTo(tp.second);
  65. }
  66.  
  67. @Override
  68. public String toString() {
  69. return first + "\t" + second;
  70. }
  71.  
  72. }

  以上可以看出,主要是要实现5个方法,都是重写方法,其中序列化的write()、readFields()2个方法,排序的compareTo(),以及hashCode()和equals()2两个基本方法。

  

五、序列化框架Avro

  可参考:Avro总结(RPC/序列化)

  http://www.open-open.com/lib/view/open1369363962228.html

六、SequenceFile MapFile

SequenceFile

  SequenceFile是一个由二进制序列化过的key/value的字节流组成的文本存储文件;在map/reduce过程中,map处理文件的临时输出就是使用SequenceFile处理过的。

  用途:

    1、纯文本不合适记录二进制类型的数据,这种情况下,Hadoop的SequenceFile类非常合适,为二进制键/值对提供一个持久数据结构。并可对key value压缩处理。

    2、SequenceFile可作为小文件的容器,HDFS和MR更适合处理大文件。

  定位文件位置的两种方法:

    1、seek(long poisitiuion):poisition必须是记录的边界,否则调用next()方法时会报错

    2、sync(long poisition):Poisition可以不是记录的边界,如果不是边界,会定位到下一个同步点,如果Poisition之后没有同步点了,会跳转到文件的结尾位置

  三种压缩态:

    Uncompressed – 未进行压缩的状

    Record compressed - 对每一条记录的value值进行了压缩(文件头中包含上使用哪种压缩算法的信息)

    Block compressed – 当数据量达到一定大小后,将停止写入一个block压缩;整体压缩的方法是把所有的keylength,key,vlength,value 分别合在一起进行整体压缩,块的压缩效率要比记录的压缩效率高;

  

   写入SequenceFile:

  1. package com.lcy.hadoop.io;
  2.  
  3. import java.net.URI;
  4.  
  5. import org.apache.hadoop.conf.Configuration;
  6. import org.apache.hadoop.fs.FileSystem;
  7. import org.apache.hadoop.fs.Path;
  8. import org.apache.hadoop.io.IOUtils;
  9. import org.apache.hadoop.io.IntWritable;
  10. import org.apache.hadoop.io.SequenceFile;
  11. import org.apache.hadoop.io.Text;
  12.  
  13. public class SequenceFileWriteDemo {
  14.  
  15. private static final String [] DATA={
  16. "One,two,buckle my shoe",
  17. "Three,four,shut the door",
  18. "Five,six,pick up sticks",
  19. "Seven,eight,lay them straight",
  20. "Nine,ten,a big fat hen"
  21. };
  22.  
  23. public static void main(String[] args) throws Exception{
  24. // TODO Auto-generated method stub
  25. String uri=args[0];
  26. Configuration conf=new Configuration();
  27. FileSystem fs=FileSystem.get(URI.create(uri),conf);
  28. Path path=new Path(uri);
  29.  
  30. IntWritable key=new IntWritable();
  31. Text value=new Text();
  32. SequenceFile.Writer writer=null;
  33. try{
  34. writer=SequenceFile.createWriter(fs,conf,path,key.getClass(),value.getClass());
  35. for(int i=0;i<100;i++){
  36. key.set(100-i);
  37. value.set(DATA[i%DATA.length]);
  38. System.out.printf("[%s]\t%s\t%s\n",writer.getLength(),key,value);
  39. writer.append(key, value);
  40. }
  41. }finally{
  42. IOUtils.closeStream(writer);
  43. }
  44. }
  45. }

   读取SequenceFile:

  1. //从头到尾读取顺序文件就是创建SequenceFile.Reader实例后反复调用next()方法迭代读取记录
  2. //如果next()方法返回的是非null对象,则可以从该数据流中读取键值对
  3.  
  4. package com.lcy.hadoop.io;
  5.  
  6. import java.net.URI;
  7.  
  8. import org.apache.hadoop.conf.Configuration;
  9. import org.apache.hadoop.fs.FileSystem;
  10. import org.apache.hadoop.fs.Path;
  11. import org.apache.hadoop.io.IOUtils;
  12. import org.apache.hadoop.io.SequenceFile;
  13. import org.apache.hadoop.io.Writable;
  14. import org.apache.hadoop.util.ReflectionUtils;
  15.  
  16. public class SequenceFileReadDemo {
  17.  
  18. public static void main(String[] args) throws Exception{
  19. // TODO Auto-generated method stub
  20. String uri=args[0];
  21. Configuration conf=new Configuration();
  22. FileSystem fs=FileSystem.get(URI.create(uri),conf);
  23. Path path=new Path(uri);
  24. SequenceFile.Reader reader=null;
  25. try{
  26. reader=new SequenceFile.Reader(fs, path, conf);
  27. Writable key=(Writable)ReflectionUtils.newInstance(reader.getKeyClass(), conf);
  28. Writable value=(Writable)ReflectionUtils.newInstance(reader.getValueClass(), conf);
  29. long position=reader.getPosition();
  30. while(reader.next(key,value)){
  31. String syncSeen=reader.syncSeen()?"*":" ";
  32. System.out.printf("[%s%s]\t%s\t%s\n",position,syncSeen,key,value);
  33. position=reader.getPosition();
  34. }
  35. }finally{
  36. IOUtils.closeStream(reader);
  37. }
  38. }
  39. }

   在命令行下,可有-text 参数来查看gzip压缩文件 和 序列文件,否则直接查看可能是乱码;

  

   SequenceFile内部格式:  

     组成:

      SequenceFile由一个header 和 随后的 多条记录组成;

      header包含:前三字节是SequenceFile文件代码SEQ;版本号;key value类型;压缩细节; 

      同步标识sync:用于读取文件时能够从任意位置开始识别记录边界。同步标识位于记录和记录之间,因为额外存储开销(1%),没必要在每个记录后都有标识

     1、 record压缩:

          

        record压缩 和 无压缩基本相同,只不过是值value用文件头中定义的codec压缩过,而其它key、length都不变;

   

      2、block压缩:

      

      

        block压缩是指一次性压缩多条记录,压缩率较高;

        压缩时是向一个压缩块中添加记录,直到压缩后的block大于定义的值(默认为1MB)每个新块的开始都会有一个同步标识;

        压缩后的格式:首先是一个指示数据块中字节数的字段;紧接着是4个字段(键长,键;值长,值 )         

        

MapFile

    MapFile是已排序过的SequenceFile,它含有索引,可快速随机读取(二分查找);

    创建一个map类型的文件,实际会合成一个文件夹,文件夹中包含两部分:

      

      

     MapFile的读类型SequenceFile,别外包含两个随机读取key的方法:

      public Writable get(WritableComparable key, Writable val) throws IOException

      public Writable getClosest(WritableComparable key, Writable val) throws IOException//返回最近的key,不会因为找不到返回null;

Hadoop中序列化与Writable接口的更多相关文章

  1. Hadoop序列化与Writable接口(二)

    Hadoop序列化与Writable接口(二) 上一篇文章Hadoop序列化与Writable接口(一)介绍了Hadoop序列化,Hadoop Writable接口以及如何定制自己的Writable类 ...

  2. Hadoop序列化与Writable接口(一)

    Hadoop序列化与Writable接口(一) 序列化 序列化(serialization)是指将结构化的对象转化为字节流,以便在网络上传输或者写入到硬盘进行永久存储:相对的反序列化(deserial ...

  3. hadoop中的序列化与Writable接口

    本文地址:http://www.cnblogs.com/archimedes/p/hadoop-writable-interface.html,转载请注明源地址. 简介 序列化和反序列化就是结构化对象 ...

  4. hadoop中实现定制Writable类

    Hadoop中有一套Writable实现可以满足大部分需求,但是在有些情况下,我们需要根据自己的需要构造一个新的实现,有了定制的Writable,我们就可以完全控制二进制表示和排序顺序. 为了演示如何 ...

  5. Hadoop中Writable类之四

    1.定制Writable类型 Hadoop中有一套Writable实现,例如:IntWritable.Text等,但是,有时候可能并不能满足自己的需求,这个时候,就需要自己定制Writable类型. ...

  6. Hadoop Serialization hadoop序列化详解(最新版) (1)【java和hadoop序列化比较和writable接口】

    初学java的人肯定对java序列化记忆犹新.最开始很多人并不会一下子理解序列化的意义所在.这样子是因为很多人还是对java最底层的特性不是特别理解,当你经验丰富,对java理解更加深刻之后,你就会发 ...

  7. 为什么hadoop中用到的序列化不是java的serilaziable接口去序列化而是使用Writable序列化框架

    继上一个模块之后,此次分析的内容是来到了Hadoop IO相关的模块了,IO系统的模块可谓是一个比较大的模块,在Hadoop Common中的io,主要包括2个大的子模块构成,1个是以Writable ...

  8. Hadoop基础-序列化与反序列化(实现Writable接口)

    Hadoop基础-序列化与反序列化(实现Writable接口) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.序列化简介 1>.什么是序列化 序列化也称串行化,是将结构化 ...

  9. hadoop中的序列化与Writable类

    本文地址:http://www.cnblogs.com/archimedes/p/hadoop-writable-class.html,转载请注明源地址. hadoop中自带的org.apache.h ...

随机推荐

  1. 如何将一个int转换成cstring

    如:int a = 5;CString b;b.Format("%d",a);补充:如果a是double,或a是float的就是:b.Format("%f",a ...

  2. Spoj-ANTP Mr. Ant & His Problem

    Mr. Ant has 3 boxes and the infinite number of marbles. Now he wants to know the number of ways he c ...

  3. Nk 1430 Fibonacci(二分矩阵乘幂)

    AC代码: #include<iostream> using namespace std; ][]; ][]; ][]; ][]; void binary(int n) { int i,j ...

  4. Java内存区域划分、内存分配原理(深入理解JVM一)

    Java虚拟机在执行Java的过程中会把管理的内存划分为若干个不同的数据区域.这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,而有的区域则依赖线程的启动和结束而创建和销 ...

  5. eq=等于gt=大于lt=小于的英文全称

    EQ: Equal GT: Greater Than LT: Less than 知道全称就不会忘记

  6. Java游戏服务器搭建

    一.前言 此游戏服务器架构是一个单服的形式,也就是说所有游戏逻辑在一个工程里,没有区分登陆服务器.战斗服务器.世界服务器等.此架构已成功应用在了多款页游服务器 .在此框架中没有实现相关业务逻辑,只有简 ...

  7. 数字IC设计入门必备——VIM自定义模板调用与VCS基本仿真操作示例

    一.前言 毕业论文答辩结束,闲下来写篇文章.芯片研发人员都在Linux系统下借助各种EDA工具和代码语言完成工作,因此提高代码开发效率,熟练运用开发工具是十分必要的.本文讲述VIM编辑神器的veril ...

  8. <!--#include 引入失败

    在html中使用了<!--#include file="a.html">,结果发现页面上并没有引入到a.html页面,F12看是以注释的形式展示出来了,百度了很久. 最 ...

  9. 【面试 struts2】【第三篇】struts2的问题

    1.struts2的工作流程 1>客户端浏览器发出HTTP请求. 2>根据web.xml配置,该请求被FilterDispatcher接收 3>根据struts.xml配置,找到需要 ...

  10. Activiti 5.17 实体对象与类和数据库表的映射

    一.Activiti 5.17 mybatis的mapping文件声明映射的实体对象关系. <configuration><settings><settingname=& ...