自定义Writable
hadoop
虽然已经实现了一些非常有用的Writable,而且你可以使用他们的组合做很多事情,但是如果你想构造一些更加复杂的结果,你可以自定义
Writable来达到你的目的,我们以注释的方式对自定义Writable进行讲解(不许说我只帖代码占篇幅哦,姿势写在注释里了):
Writable对象是可更改的而且经常被重用,因此尽量避免在write和readFields中分配对象。
自定义RawComparatorWritable
上
面的EmploeeWritable已经可以跑的很溜了,但是还是有优化的空间,当作为MapReduce里的key,需要进行比较时,因为他已经被序列
化,想要比较他们,那么首先要先反序列化成一个对象,然后再调用compareTo对象进行比较,但是这样效率太低了,有没有可能可以直接比较序列化后的
结果呢,答案是肯定的,可以。
我们只需要把EmploeeWritable的序列化后的结果拆成成员对象,然后比较成员对象即可,那么来看代码(讲解再次写在注释里):
- public static class Comparator extends WritableComparator{
- private static final Text.Comparator TEXT_COMPARATOR= new Text.Comparator();
-
- protected Comparator() {
- super(EmploeeWritable.class);
- }
-
- @Override
- public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
- try {
- /**
- * name是Text类型,Text是标准的UTF-8字节流,
- * 由一个变长整形开头表示Text中文本所需要的长度,接下来就是文本本身的字节数组
- * decodeVIntSize返回变长整形的长度,readVInt表示文本字节数组的长度,加起来就是第一个成员name的长度
- */
- int nameL1= WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);
- int nameL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);
- //和compareTo方法一样,先比较name
- int cmp = TEXT_COMPARATOR.compare(b1,s1,nameL1,b2,s2,nameL2);
- if(cmp!=0){
- return cmp;
- }
- //再比较role
- return TEXT_COMPARATOR.compare(b1,s1+nameL1,l1-nameL1,b2,s2+nameL2,l2-nameL2);
- } catch (IOException e) {
- throw new IllegalArgumentException();
- }
- }
-
- static {
- //注册raw comprator,更象是绑定,这样MapReduce使用EmploeeWritable时就会直接调用Comparator
- WritableComparator.define(EmploeeWritable.class,new Comparator());
- }
- }
我
们没有直接去实现RawComparator而是继承于WritableComparator,因为WritableComparator提供了很多便捷
的方法,并且对compare有个默认的实现。写compare方法时一定要小心谨慎,因为都是在字节上操作,可以好好参考下源代码里的一些
Writable中Comparator的写法,另外多看下WritableUtils也是由必要的,他里面有很多简便的方法可以使用。
有时候,除了默认的comparator,你可能还需要一些自定义的comparator来生成不同的排序队列,看一下下面这个示例,只比较name,两个compare是同一意思,都是比较name大小:
- public static class NameComparator extends WritableComparator{
- private static final Text.Comparator TEXT_COMPARATOR= new Text.Comparator();
-
- protected NameComparator() {
- super(EmploeeWritable.class);
- }
-
- @Override
- public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
- try {
- int nameL1= WritableUtils.decodeVIntSize(b1[s1])+readVInt(b1,s1);
- int nameL2=WritableUtils.decodeVIntSize(b2[s2])+readVInt(b2,s2);
- return TEXT_COMPARATOR.compare(b1,s1,nameL1,b2,s2,nameL2);
- } catch (IOException e) {
- throw new IllegalArgumentException();
- }
- }
-
- @Override
- public int compare(WritableComparable a, WritableComparable b) {
- if(a instanceof EmploeeWritable && b instanceof EmploeeWritable){
- return ((EmploeeWritable)a).name.compareTo(((EmploeeWritable)b).name);
- }
- return super.compare(a,b);
- }
- }
转载自:http://blog.csdn.net/lastsweetop/article/details/9360075