自定义Writable

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

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

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. protected Comparator() {
  4. super(EmploeeWritable.class);
  5. }
  6. @Override
  7. public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
  8. try {
  9. /**
  10. * name是Text类型,Text是标准的UTF-8字节流,
  11. * 由一个变长整形开头表示Text中文本所需要的长度,接下来就是文本本身的字节数组
  12. * decodeVIntSize返回变长整形的长度,readVInt表示文本字节数组的长度,加起来就是第一个成员name的长度
  13. */
  14. int nameL1= WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);
  15. int nameL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);
  16. //和compareTo方法一样,先比较name
  17. int cmp = TEXT_COMPARATOR.compare(b1,s1,nameL1,b2,s2,nameL2);
  18. if(cmp!=0){
  19. return cmp;
  20. }
  21. //再比较role
  22. return TEXT_COMPARATOR.compare(b1,s1+nameL1,l1-nameL1,b2,s2+nameL2,l2-nameL2);
  23. } catch (IOException e) {
  24. throw new IllegalArgumentException();
  25. }
  26. }
  27. static {
  28. //注册raw comprator,更象是绑定,这样MapReduce使用EmploeeWritable时就会直接调用Comparator
  29. WritableComparator.define(EmploeeWritable.class,new Comparator());
  30. }
  31. }

我们没有直接去实现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. protected NameComparator() {
  4. super(EmploeeWritable.class);
  5. }
  6. @Override
  7. public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
  8. try {
  9. int nameL1= WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);
  10. int nameL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);
  11. return TEXT_COMPARATOR.compare(b1,s1,nameL1,b2,s2,nameL2);
  12. } catch (IOException e) {
  13. throw new IllegalArgumentException();
  14. }
  15. }
  16. @Override
  17. public int compare(WritableComparable a, WritableComparable b) {
  18. if(a instanceof EmploeeWritable && b instanceof  EmploeeWritable){
  19. return ((EmploeeWritable)a).name.compareTo(((EmploeeWritable)b).name);
  20. }
  21. return super.compare(a,b);
  22. }
  23. }

自定义Writable、RawComparatorWritable、comparators(转)的更多相关文章

  1. 5.3.3 自定义writable和RawComparatorWritable

    5.3.3 自定义writable (1)构造员工writable Hadoop虽然已经实现了一些非常有用的Writable,而且你可以使用他们的组合做很多事情,但是如果你想构造一些更加复杂的结果,你 ...

  2. 读取SequenceFile中自定义Writable类型值

    1)hadoop允许程序员创建自定义的数据类型,如果是key则必须要继承WritableComparable,因为key要参与排序,而value只需要继承Writable就可以了.以下定义一个Doub ...

  3. Hadoop Serialization -- hadoop序列化详解 (3)【ObjectWritable,集合Writable以及自定义的Writable】

    前瞻:本文介绍ObjectWritable,集合Writable以及自定义的Writable TextPair 回顾: 前面了解到hadoop本身支持java的基本类型的序列化,并且提供相应的包装实现 ...

  4. 自定义排序及Hadoop序列化

    自定义排序 将两列数据进行排序,第一列按照升序排列,当第一列相同时,第二列升序排列. 在map和reduce阶段进行排序时,比较的是k2.v2是不参与排序比较的.如果要想让v2也进行排序,需要把k2和 ...

  5. MapReduce实例-倒排索引

    环境: Hadoop1.x,CentOS6.5,三台虚拟机搭建的模拟分布式环境 数据:任意数量.格式的文本文件(我用的四个.java代码文件) 方案目标: 根据提供的文本文件,提取出每个单词在哪个文件 ...

  6. 重新认识mapreduce

    写这篇文章,是因为最近遇到了mapreduce的二次排序问题.以前的理解不完全正确.首先看一下mapreduce的过程 相信这张图熟悉MR的人都应该见过,再来一张图 wordcount也不细说了,ha ...

  7. [大牛翻译系列]Hadoop(13)MapReduce 性能调优:优化洗牌(shuffle)和排序阶段

    6.4.3 优化洗牌(shuffle)和排序阶段 洗牌和排序阶段都很耗费资源.洗牌需要在map和reduce任务之间传输数据,会导致过大的网络消耗.排序和合并操作的消耗也是很显著的.这一节将介绍一系列 ...

  8. 一站式Hadoop&Spark云计算分布式大数据和Android&HTML5移动互联网解决方案课程(Hadoop、Spark、Android、HTML5)V2的第一门课程

    Hadoop是云计算的事实标准软件框架,是云计算理念.机制和商业化的具体实现,是整个云计算技术学习中公认的核心和最具有价值内容. 如何从企业级开发实战的角度开始,在实际企业级动手操作中深入浅出并循序渐 ...

  9. [BigData]关于Hadoop学习笔记第三天(PPT总结)(一)

     课程安排 MapReduce原理*** MapReduce执行过程** 数据类型与格式*** Writable接口与序列化机制*** ---------------------------加深拓展- ...

随机推荐

  1. 2014年最大福利:185个Google排名因素!免费电子书下载

    本博开张以来最大规模的干货放送!新手老手都有用! 不要再去追求PR了,不要再去发博客发论坛发外链了! 关注真正有用的Google排名因素! 整整185项,每一项都附带说明,必要的地方会给出一些附加的阅 ...

  2. Magento修改邮件模板内容

    Magento 默认邮件模板 都是带着官方的标志和一些官方的基本信息.为了建立品牌形象我们需要把邮件模板中的所有官方信息换成自己的信息.修改步骤如下: 1.找到Magento的邮件模板文件(这里以 e ...

  3. Selenium2学习-003-WebUI自动化实战实例-001-百度搜索

    此文主要通过百度搜索功能,进行 Selenium2 的实战实例讲解,文中所附源代码于 2015-01-16 02:01 亲测通过,敬请亲们阅览.希望能对初学 Selenium2 UI 自动化测试编程的 ...

  4. mybatis的xlm的sql

    <sqlMap namespace="egis.scms.order">    <typeAlias alias="ScmsOrderDTO" ...

  5. 用MFC时,如果程序崩溃,检查内存,然后注意GDI数量,在任务管理器里选项-查看列-GDI数量

    用MFC时,如果程序崩溃,检查内存,然后注意GDI数量,在任务管理器里选项-查看列-GDI数量

  6. IEnumerable和IQueryable的区别

    转自:http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...

  7. mysql 授权 user@'%' 为什么登陆的时候localhost 不行呢???

    公司业务服务器还没迁移到阿里云上的时候,创建的一个用户明明是所有的,但是本机登陆就是不行,一直也搞不懂原因 今天才知道 原来 %不包括 localhost mysql> grant all on ...

  8. yum报错: Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again

    在Centos 5.x或6.x上安装RHEL EPEL Repo repository,资源库,源的意思.RHEL EPEL(Extra Packages for Enterprise Linux)  ...

  9. IE、chrome、火狐中如何调试javascript脚本

    1.  IE中点击"F12",在弹出页面中调试javascript脚本 2. chrome中点击"F12",在弹出页面中调试javascript脚本 3.  火 ...

  10. Perl Print Win32 Console Windows 控制台 print Unicode 问题

    参考资料: https://stackoverflow.com/questions/15224400/perl-on-windows-problems-with-encoding https://te ...