立即注册 登录
About云-梭伦科技 返回首页

不羁的青春 https://www.aboutyun.com/?4073 [收藏] [复制] [分享] [RSS] 不要在该奋斗的年纪而去选择安逸的生活!!!

日志

hadoop序列化(三)-----自定义Writable

热度 1已有 1777 次阅读2016-1-21 14:36 |个人分类:HDFS| 自定义Writable

自定义Writable

hadoop 虽然已经实现了一些非常有用的Writable,而且你可以使用他们的组合做很多事情,但是如果你想构造一些更加复杂的结果,你可以自定义 Writable来达到你的目的,我们以注释的方式对自定义Writable进行讲解(不许说我只帖代码占篇幅哦,姿势写在注释里了):

  1. package com.sweetop.styhadoop;  
  2.   
  3. import org.apache.hadoop.io.Text;  
  4. import org.apache.hadoop.io.WritableComparable;  
  5.   
  6. import java.io.DataInput;  
  7. import java.io.DataOutput;  
  8. import java.io.IOException;  
  9.   
  10. /** 
  11.  * Created with IntelliJ IDEA. 
  12.  * User: lastsweetop 
  13.  * Date: 13-7-17 
  14.  * Time: 下午8:50 
  15.  * To change this template use File | Settings | File Templates. 
  16.  */  
  17. public class EmploeeWritable implements WritableComparable<EmploeeWritable>{  
  18.   
  19.     private Text name;  
  20.     private Text role;  
  21.   
  22.     /** 
  23.      * 必须有默认的构造器皿,这样Mapreduce方法才能创建对象,然后通过readFields方法从序列化的数据流中读出进行赋值 
  24.      */  
  25.     public EmploeeWritable() {  
  26.         set(new Text(),new Text());  
  27.     }  
  28.   
  29.     public EmploeeWritable(Text name, Text role) {  
  30.         set(name,role);  
  31.     }  
  32.   
  33.     public void set(Text name,Text role) {  
  34.         this.name = name;  
  35.         this.role = role;  
  36.     }  
  37.   
  38.     public Text getName() {  
  39.         return name;  
  40.     }  
  41.   
  42.     public Text getRole() {  
  43.         return role;  
  44.     }  
  45.   
  46.     /** 
  47.      * 通过成员对象本身的write方法,序列化每一个成员对象到输出流中 
  48.      * @param dataOutput 
  49.      * @throws IOException 
  50.      */  
  51.     @Override  
  52.     public void write(DataOutput dataOutput) throws IOException {  
  53.         name.write(dataOutput);  
  54.         role.write(dataOutput);  
  55.     }  
  56.   
  57.     /** 
  58.      * 同上调用成员对象本身的readFields方法,从输入流中反序列化每一个成员对象 
  59.      * @param dataInput 
  60.      * @throws IOException 
  61.      */  
  62.     @Override  
  63.     public void readFields(DataInput dataInput) throws IOException {  
  64.         name.readFields(dataInput);  
  65.         role.readFields(dataInput);  
  66.     }  
  67.   
  68.     /** 
  69.      * implements WritableComparable必须要实现的方法,用于比较  排序 
  70.      * @param emploeeWritable 
  71.      * @return 
  72.      */  
  73.     @Override  
  74.     public int compareTo(EmploeeWritable emploeeWritable) {  
  75.         int cmp = name.compareTo(emploeeWritable.name);  
  76.         if(cmp!=0){  
  77.             return cmp;  
  78.         }  
  79.         return role.compareTo(emploeeWritable.role);  
  80.     }  
  81.   
  82.     /** 
  83.      * MapReduce需要一个分割者(Partitioner)把map的输出作为输入分成一块块的喂给多个reduce) 
  84.      * 默认的是HashPatitioner,他是通过对象的hashcode函数进行分割,所以hashCode的好坏决定 
  85.      * 了分割是否均匀,他是一个很关键性的方法。 
  86.      * @return 
  87.      */  
  88.     @Override  
  89.     public int hashCode() {  
  90.         return name.hashCode()*163+role.hashCode();  
  91.     }  
  92.   
  93.     @Override  
  94.     public boolean equals(Object o) {  
  95.         if(o instanceof EmploeeWritable){  
  96.             EmploeeWritable emploeeWritable=(EmploeeWritable)o;  
  97.             return name.equals(emploeeWritable.name) && role.equals(emploeeWritable.role);  
  98.         }  
  99.         return false;  
  100.     }  
  101.   
  102.     /** 
  103.      * 如果你想自定义TextOutputformat作为输出格式时的输出,你需要重写toString方法 
  104.      * @return 
  105.      */  
  106.     @Override  
  107.     public String toString() {  
  108.         return name+"\t"+role;  
  109.     }  
  110. }  
Writable对象是可更改的而且经常被重用,因此尽量避免在write和readFields中分配对象。

自定义RawComparatorWritable
上 面的EmploeeWritable已经可以跑的很溜了,但是还是有优化的空间,当作为MapReduce里的key,需要进行比较时,因为他已经被序列 化,想要比较他们,那么首先要先反序列化成一个对象,然后再调用compareTo对象进行比较,但是这样效率太低了,有没有可能可以直接比较序列化后的 结果呢,答案是肯定的,可以。
我们只需要把EmploeeWritable的序列化后的结果拆成成员对象,然后比较成员对象即可,那么来看代码(讲解再次写在注释里):
  1. public static class Comparator extends WritableComparator{  
  2.         private static final Text.Comparator TEXT_COMPARATOR= new Text.Comparator();  
  3.   
  4.         protected Comparator() {  
  5.             super(EmploeeWritable.class);  
  6.         }  
  7.   
  8.         @Override  
  9.         public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {  
  10.             try {  
  11.                 /** 
  12.                  * name是Text类型,Text是标准的UTF-8字节流, 
  13.                  * 由一个变长整形开头表示Text中文本所需要的长度,接下来就是文本本身的字节数组 
  14.                  * decodeVIntSize返回变长整形的长度,readVInt表示文本字节数组的长度,加起来就是第一个成员name的长度 
  15.                  */  
  16.                 int nameL1= WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);  
  17.                 int nameL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);  
  18.                 //和compareTo方法一样,先比较name  
  19.                 int cmp = TEXT_COMPARATOR.compare(b1,s1,nameL1,b2,s2,nameL2);  
  20.                 if(cmp!=0){  
  21.                     return cmp;  
  22.                 }  
  23.                 //再比较role  
  24.                 return TEXT_COMPARATOR.compare(b1,s1+nameL1,l1-nameL1,b2,s2+nameL2,l2-nameL2);  
  25.             } catch (IOException e) {  
  26.                 throw new IllegalArgumentException();  
  27.             }  
  28.         }  
  29.   
  30.         static {  
  31.             //注册raw comprator,更象是绑定,这样MapReduce使用EmploeeWritable时就会直接调用Comparator  
  32.             WritableComparator.define(EmploeeWritable.class,new Comparator());  
  33.         }  
  34.     }  
我 们没有直接去实现RawComparator而是继承于WritableComparator,因为WritableComparator提供了很多便捷 的方法,并且对compare有个默认的实现。写compare方法时一定要小心谨慎,因为都是在字节上操作,可以好好参考下源代码里的一些 Writable中Comparator的写法,另外多看下WritableUtils也是由必要的,他里面有很多简便的方法可以使用。

自定义comparators
有时候,除了默认的comparator,你可能还需要一些自定义的comparator来生成不同的排序队列,看一下下面这个示例,只比较name,两个compare是同一意思,都是比较name大小:
  1. public static class NameComparator extends WritableComparator{  
  2.         private static final Text.Comparator TEXT_COMPARATOR= new Text.Comparator();  
  3.   
  4.         protected NameComparator() {  
  5.             super(EmploeeWritable.class);  
  6.         }  
  7.   
  8.         @Override  
  9.         public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {  
  10.             try {  
  11.                 int nameL1= WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);  
  12.                 int nameL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);  
  13.                 return TEXT_COMPARATOR.compare(b1,s1,nameL1,b2,s2,nameL2);  
  14.             } catch (IOException e) {  
  15.                 throw new IllegalArgumentException();  
  16.             }  
  17.         }  
  18.   
  19.         @Override  
  20.         public int compare(WritableComparable a, WritableComparable b) {  
  21.             if(a instanceof EmploeeWritable && b instanceof  EmploeeWritable){  
  22.                 return ((EmploeeWritable)a).name.compareTo(((EmploeeWritable)b).name);  
  23.             }  
  24.             return super.compare(a,b);  
  25.         }  
  26.     } 


转载自:http://blog.csdn.net/lastsweetop/article/details/9360075

1

路过

雷人

握手

鲜花

鸡蛋

刚表态过的朋友 (1 人)

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 立即注册

关闭

推荐上一条 /2 下一条