Hadoop学习三十七:HBase比较负数

一.HBase存储

     那么Integer(-1)在HBase里将被存储为\xFF\xFF\xFF\xFF,Integer(1)在Hbase里将被存储为\x00\x00\x00\x01。

     再来看看在比较大小时的PureJavaComparer.compareTo,会将字节码,通过&0xff,转换成一个无符号位的正数。此时将出现\xFF\xFF\xFF\xFF & 0xff = \xFF = 255,x00\x00\x00\x01 & 0xff = \x01 = 1,所以-1>1。

     最终,HBase认为数值类从小到大为:0 1 +∞ -∞ -1

二.怎么解决

      至少有三种思路

  1. 细分四种查询条件,过滤掉多查的,加上少查的。如查询>某一正数时,要加上<+∞这个条件来过滤掉[-∞ -1]。显然这种方法管用但过于繁琐,新增了许多过滤器对regionserver也是一种压力。
  2. 存储时将负数转成正数,将正数转成更大的正数,查询时根据相同规则转换查询条件,查询出来的结果再反转回去。这样存储的结果就只能对查询有用了,其它系统使用你这些HBase数据时,它并不一定知道你的存储规则。
  3. 自己写一个数字类比较器NumberComparator,子类DoubleComparator,IntegerComparator等里重写compareTo方法。这个也是我采用的方式。

三.关于比较器 等于

      在容器里面,会涉及到equals,compareTo等方法来比较两个数的等于关系和大小关系。

      容器A里已经插入1 2 3三个数据,要插入4的时候,会把4当做this,与1 2 3分别equals或者compareTo,即4.compareTo(1)。所以我们重写equals,compareTo等方法时,也是this 4在前,参数1在后。如果你想得到相反的顺序,就把参数放前,this放后。

package org.apache.hadoop.hbase.filter;

import org.apache.hadoop.hbase.util.Bytes;


public class DoubleComparator extends NumberComparator {

	public DoubleComparator() {
	}

	public DoubleComparator(final byte[] value) {
		super(value);
	}
	
	@Override
	public int compareTo(byte[] value, int offset, int length) {
		double d1 = Bytes.toDouble(super.value);
		double d2 = Bytes.toDouble(value, offset);
		if (d1 < d2)
            return -1;		 // Neither val is NaN, thisVal is smaller
        if (d1 > d2)
            return 1;		 // Neither val is NaN, thisVal is larger

        long thisBits = Double.doubleToLongBits(d1);
        long anotherBits = Double.doubleToLongBits(d2);

        return (thisBits == anotherBits ?  0 : // Values are equal
                (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
                 1));          
	}


}

相关推荐