自定义Hadoop的可序列化类

简介:

java原生语言中要想一个自定义类可序列化,很简单,只要让这个类实现java.io.Serializable接口就可以了,但是在Hadoop框架中,要想让自定义类可以被序列化,我们必须手动让其实现WritableCompable接口并且实现write(),readFields(),compareTo()方法。

下面就是一个我们自定义的可序列化的类:

 
 
  1. /*  
  2.  */ 
  3. package com.charles.writable; 
  4.  
  5. import java.io.DataInput; 
  6. import java.io.DataOutput; 
  7. import java.io.IOException; 
  8.  
  9.  
  10. import org.apache.hadoop.io.IntWritable; 
  11. import org.apache.hadoop.io.Text; 
  12. import org.apache.hadoop.io.WritableComparable; 
  13.  
  14. /** 
  15.  * 
  16.  * Description: 这是自定义的Hadoop序列化类,它可以用Hadoop序列化反序列化这个类 
  17.  * 
  18.  * @author charles.wang 
  19.  * @created Jun 2, 2012 11:19:25 AM 
  20.  *  
  21.  */ 
  22. public class PersonWritable implements WritableComparable<PersonWritable> { 
  23.  
  24.     private Text name; 
  25.     private IntWritable age; 
  26.     private Text title; 
  27.      
  28.     public PersonWritable(){ 
  29.        set("someperson",0,"sometitle"); 
  30.     } 
  31.      
  32.     public PersonWritable(String name ,int age, String title){ 
  33.         set(name,age,title); 
  34.     } 
  35.      
  36.      
  37.     public void set(String name ,int age,String title){ 
  38.         this.name =  new Text(name); 
  39.          
  40.         age=(age>0)?age:1
  41.         this.age = new IntWritable(age); 
  42.          
  43.         this.title=  new Text(title); 
  44.     } 
  45.      
  46.      
  47.     /** 
  48.      *  这个方法用于定义序列化过程,它把这个对象的所有字段依次序列化 
  49.      */ 
  50.     @Override 
  51.     public void write(DataOutput out) throws IOException { 
  52.         // TODO Auto-generated method stub 
  53.          
  54.         name.write(out); 
  55.         age.write(out); 
  56.         title.write(out); 
  57.          
  58.     } 
  59.  
  60.     /** 
  61.      *  这个方法用于定义反序列化过程,它吧序列化后的DataInput的内容还原为Hadoop对象 
  62.      */ 
  63.     @Override 
  64.     public void readFields(DataInput in) throws IOException { 
  65.         // TODO Auto-generated method stub 
  66.          
  67.         name.readFields(in); 
  68.         age.readFields(in); 
  69.         title.readFields(in); 
  70.          
  71.     } 
  72.  
  73.     /** 
  74.      * 这是用于2个序列化对象之间的比较 
  75.      */ 
  76.     @Override 
  77.     public int compareTo(PersonWritable pO) { 
  78.         // TODO Auto-generated method stub 
  79.         int cmp1 = name.compareTo(pO.name); 
  80.         if(cmp1 != 0){ 
  81.             return cmp1; 
  82.         } 
  83.          
  84.         int cmp2 = age.compareTo(pO.age); 
  85.         if(cmp2 !=0){ 
  86.             return cmp2; 
  87.         } 
  88.          
  89.         int cmp3 = title.compareTo(pO.title); 
  90.         return cmp3; 
  91.     } 
  92.      
  93.     /** 
  94.      * 定义hashcode是个好习惯,我们还是使用最常用的字段分别乘以不同的素数然后相加的方法 
  95.      */ 
  96.     @Override 
  97.     public int hashCode(){ 
  98.         return name.hashCode()*71+ age.hashCode()*73+title.hashCode()*127
  99.     } 
  100.      
  101.     @Override 
  102.     public boolean equals (Object o ){ 
  103.         if ( o instanceof PersonWritable){ 
  104.              
  105.             PersonWritable pw = (PersonWritable) o; 
  106.             boolean equals = name.equals(pw.name) && age.equals(pw.age) && title.equals(pw.title); 
  107.             return equals; 
  108.         } 
  109.         return false
  110.     } 
  111.      
  112.     @Override 
  113.     public String toString(){ 
  114.         StringBuffer sb = new StringBuffer(); 
  115.         sb.append("["); 
  116.         sb.append("姓名: "+name+","); 
  117.         sb.append("年龄: "+age+","); 
  118.         sb.append("头衔: "+title); 
  119.         sb.append("]"); 
  120.         return sb.toString(); 
  121.     } 
  122.  

 

为了方便演示序列化前后的内容,我们定义了一个工具方法,这个方法可以用于跟踪序列化和反序列化的中间产物:

 
 
  1. /*  
  2.  */ 
  3. package com.charles.writable; 
  4.  
  5.  
  6. import java.io.ByteArrayInputStream; 
  7. import java.io.ByteArrayOutputStream; 
  8. import java.io.DataInputStream; 
  9. import java.io.DataOutputStream; 
  10. import java.io.IOException; 
  11.  
  12. import org.apache.hadoop.io.Writable; 
  13.  
  14. /** 
  15.  * 
  16.  * Description: 这个类提供了工具方法来记录序列化的轨迹 
  17.  * 因为,在hadoop中序列化和反序列化都是在Writable接口中进行的,Writable是被序列化的Hadoop对象 
  18.  * 所以我们把序列化的产物存到字节数组中从而可以捕捉到内容 
  19.  * 
  20.  * @author charles.wang 
  21.  * @created Jun 2, 2012 9:32:41 AM 
  22.  *  
  23.  */ 
  24. public class HadoopSerializationUtil { 
  25.      
  26.     //这个方法可以把Hadoop的对象(Writable表示这个是可以序列化的)序列化到字节数组中, 
  27.     //然后把字节数组中的内容返回出来 
  28.     //入参,被序列化的数值对象 
  29.     //返回值:序列化后的字节数组 
  30.     public static byte[] serialize(Writable writable) throws IOException { 
  31.         //创建一个字节数组 
  32.          ByteArrayOutputStream out = new ByteArrayOutputStream(); 
  33.          //创建一个DataOutputStream,并且包装字节数组,用于存放序列化后的字节流 
  34.          DataOutputStream dataout =  new DataOutputStream(out); 
  35.          //让参数的Hadoop对象序列化到字节流中 
  36.          writable.write(dataout); 
  37.          dataout.close(); 
  38.          //返回序列化后的字节流 
  39.          return out.toByteArray(); 
  40.     } 
  41.      
  42.     //这个方法用于反序列化一个字节数组成Hadoop Writable对象 
  43.     //入参1:反序列化后的Writable对象存放在这个参数中 
  44.     //入参2:被反序列化的字节数组 
  45.     public static void deserialize(Writable writable,byte[] bytes) throws Exception{ 
  46.          
  47.         //打开一个字节数组输入流让其指向即将要被处理的字节数组(第二个参数) 
  48.         ByteArrayInputStream in = new ByteArrayInputStream(bytes); 
  49.         //打开一个DataInputStream 
  50.         DataInputStream datain = new DataInputStream(in); 
  51.         //让Hadoop框架反序列化这个字节数组,还原后的Writable对象存放到第一个参数中 
  52.         writable.readFields(datain); 
  53.         datain.close(); 
  54.     } 
  55.      
  56.   
  57.  

 

最后,我们用一个Demo例子来演示序列化和反序列化我们自定义的类的对象:

 
 
  1. /*  
  2.  */ 
  3. package com.charles.writable; 
  4.  
  5. import org.apache.hadoop.util.StringUtils; 
  6.  
  7.  
  8. /** 
  9.  * 
  10.  * Description: 这个例子用于展示自定义的Hadoop序列化类是否工作正常 
  11.  * 
  12.  * @author charles.wang 
  13.  * @created Jun 2, 2012 11:40:01 AM 
  14.  *  
  15.  */ 
  16. public class HadoopObjectSerializationDemo { 
  17.       
  18.      
  19.     public static void main(String [] args) throws Exception{ 
  20.          
  21.         //第一个实验,把我们自定义的Hadoop可序列化对象进行序列化 
  22.         System.out.println("实验1: 序列化"); 
  23.         PersonWritable originalPersonWritable = new PersonWritable("Charles Wang" ,26 ,"Technical Lead"); 
  24.         String typeInfo= "被测试的自定义Hadoop可序列化类类型为: "+originalPersonWritable.getClass().getName()+"\n"
  25.         String primaryPersonWritableInfo = "序列化前对象为:  "+originalPersonWritable.toString()+"\n"
  26.         //开始序列化过程 
  27.         byte[] serializedHadoopValue =HadoopSerializationUtil.serialize(originalPersonWritable); 
  28.         String lengthInfo= "序列化后的字节数组长度为: "+serializedHadoopValue.length+"\n"
  29.         String serializeValueInfo= "序列化后的值为: " +StringUtils.byteToHexString(serializedHadoopValue)+"\n"
  30.  
  31.         System.out.println(typeInfo+primaryPersonWritableInfo+lengthInfo+serializeValueInfo+"\n"); 
  32.          
  33.         System.out.println(); 
  34.          
  35.         //第二个实验,把我们序列化之后的字节数组反序列化为原始Hadoop对象 
  36.         System.out.println("实验2:反序列化"); 
  37.         PersonWritable restoredPersonWritable = new PersonWritable(); 
  38.         String originalByteArrayInfo="被反序列化的字节数组内容为: "+StringUtils.byteToHexString(serializedHadoopValue)+"\n";
  39.         //开始反序列化过程 
  40.         HadoopSerializationUtil.deserialize(restoredPersonWritable, serializedHadoopValue); 
  41.         String restoredValueInfo = "反序列化之后的Writable对象为: "+restoredPersonWritable.toString(); 
  42.         System.out.println(originalByteArrayInfo+restoredValueInfo+"\n"); 
  43.     } 

 

最终结果如下,从而证明,我们自定义的Hadoop可序列化类是正确的:

 
 
  1. 实验1: 序列化 
  2. 被测试的自定义Hadoop可序列化类类型为: com.charles.writable.PersonWritable 
  3. 序列化前对象为:  [姓名: Charles Wang,年龄: 26,头衔: Technical Lead] 
  4. 序列化后的字节数组长度为: 32 
  5. 序列化后的值为: 0c436861726c65732057616e670000001a0e546563686e6963616c204c656164 
  6.  
  7.  
  8.  
  9. 实验2:反序列化 
  10. 被反序列化的字节数组内容为: 0c436861726c65732057616e670000001a0e546563686e6963616c204c656164 
  11. 反序列化之后的Writable对象为: [姓名: Charles Wang,年龄: 26,头衔: Technical Lead] 




本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/885468,如需转载请自行联系原作者

目录
相关文章
|
2月前
|
消息中间件 存储 负载均衡
Kafka【付诸实践 01】生产者发送消息的过程描述及设计+创建生产者并发送消息(同步、异步)+自定义分区器+自定义序列化器+生产者其他属性说明(实例源码粘贴可用)【一篇学会使用Kafka生产者】
【2月更文挑战第21天】Kafka【付诸实践 01】生产者发送消息的过程描述及设计+创建生产者并发送消息(同步、异步)+自定义分区器+自定义序列化器+生产者其他属性说明(实例源码粘贴可用)【一篇学会使用Kafka生产者】
362 4
|
8天前
|
存储 分布式计算 Hadoop
hadoop编写Reducer类
【7月更文挑战第10天】
9 3
|
8天前
|
分布式计算 Hadoop Java
hadoop编写Mapper类
【7月更文挑战第10天】
7 2
|
11天前
|
分布式计算 Hadoop Java
Hadoop编写Combiner类
【7月更文挑战第7天】
12 3
|
14天前
|
分布式计算 算法 Hadoop
Hadoop数据倾斜自定义分区器
【7月更文挑战第5天】
14 3
|
16天前
|
分布式计算 监控 Hadoop
Hadoop数据倾斜使用自定义分区器
【7月更文挑战第3天】
11 1
|
18天前
|
分布式计算 Hadoop 开发者
Hadoop数据倾斜自定义分区器
【7月更文挑战第1天】
12 1
|
1月前
|
存储 分布式计算 算法
|
21天前
|
JSON Java 数据格式
实现自定义序列化和反序列化控制的5种方式
实现自定义序列化和反序列化控制的5种方式
|
28天前
|
存储 分布式计算 Hadoop
MapReduce编程模型——自定义序列化类实现多指标统计
MapReduce编程模型——自定义序列化类实现多指标统计
18 0

相关实验场景

更多