前言 常用的六种Hbase自带的比较器:

1.BinaryComparator 使用Bytes.compareTo()比较当前值与阈值

2.BinaryComparator  类似第一种,但它从左端开始前缀匹配

3.NullComparator 只判断当前值是否是null

4.BitComparator 通过位运算操作执行位级比较

5.RegexStringComparator 根据正则表达式去匹配

6.SubStringComparator 将数据转为string,使用string的contains方法进行匹配
 

注意:后三种比较器只能与EQUAL和NOT_EQUAL运算符搭配使用,即不能进行GREATER或LESS比较运算,会产生错误。      

————摘自《Hbase权威指南》P131-P132

 

虽然HBASE提供了这么多自带的比较器,但个人感觉功能并不是很强大,比如:对行键中间连续几位进行一段区间式的查询,好似默认的比较器是无能为力的,只能采用自定义比较器实现(或许个人水平有限,未能发觉,如有不对,欢迎指正)。网上资料不多,过程一波三折.........,记之

 

1、搭建Protocol Buffers环境

使用过滤器执行查询时,比较器会被从执行的客户端传输到Hbase的服务端,最终在RegionServer上运行比较器的比较方法过滤的数据。而比较器从客户端传输到服务端,使用的序列化协议既不是json也不是xml,而是谷哥的protobuf!!!  (1M内的文本效率极高 !)

 

1.1、下载protobuf-2.5.0解压,windows下额外下载protoc-2.5.0-win32,解压后将protoc.exe 放在protobuf-2.5.0的src目录下。

1.2、接着配置环境变量Path

hbase 强制split hbase substringcomparator_比较器

 

cmd窗口使用protoc查看版本成功即可。

hbase 强制split hbase substringcomparator_java_02

 

2、创建proto文件,使用protoc命令生成java代码

 

例:TimestampBitProtos.proto
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


// This file contains protocol buffers that are used for filters


option java_package = "com.sky.cy.protos";	    //生成java代码的包名
option java_outer_classname = "TimestampBitProtos"; //生成的类名
option java_generic_services = true;
option java_generate_equals_and_hash = true;
option optimize_for = SPEED;


// This file contains protocol buffers that are used for comparators (e.g. in filters)

message TimestampBitComparator {
  required int32  skip=1;//自定义比较器中需序列化的字段
  required string data=2;//自定义比较器中需序列化的字段
}

cmd窗口中命令生成java代码 

 

 

命令:protoc.exe -I=D:/proto --java_out=D:/proto D:/proto/TimestampBitProtos.proto

 

hbase 强制split hbase substringcomparator_java_03

自定义比较器的序列化类生成完毕!

如图:

hbase 强制split hbase substringcomparator_hbase_04

 

3、创建比较器类,继承ByteArrayComparable,重写toByteArray、compareTo、parseFrom方法

 

import com.google.protobuf.InvalidProtocolBufferException;
import com.sky.cy.protos.TimestampBitProtos;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.filter.ByteArrayComparable;
import org.apache.hadoop.hbase.util.Bytes;

/**
 * @描述: 自定义比较器
 * @文件名: TimestampComparator.java
 * @创建人: wangxinxin
 * @创建时间: 2018/3/9
 * @修改人: wangxinxin
 * @修改备注: <br/>
 * <p>
 */
public class TimestampComparator extends ByteArrayComparable {


    public static final Log LOG = LogFactory.getLog(TimestampComparator.class);

    private byte[] data;

    //跳过字节数
    private int skip;


    public TimestampComparator(byte[] data) {
        super(data);
        this.data = data;
    }

    /**
     * @param data 目标时间戳
     * @param skip 跳过字节数
     */
    public TimestampComparator(byte[] data, int skip) {
        super(data);
        this.data = data;
        this.skip = skip;
    }

    @Override
    public byte[] toByteArray() {
        TimestampBitProtos.TimestampBitComparator.Builder builder = TimestampBitProtos.TimestampBitComparator.newBuilder();
        builder.setData(Bytes.toString(this.data));
        builder.setSkip(this.skip);
        return builder.build().toByteArray();
    }

    public static TimestampComparator parseFrom(byte[] pbBytes) throws DeserializationException {
        TimestampBitProtos.TimestampBitComparator prop = null;
        try {
            prop = TimestampBitProtos.TimestampBitComparator.parseFrom(pbBytes);
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
        return new TimestampComparator(Bytes.toBytes(prop.getData()), prop.getSkip());
    }

    @Override
    public int compareTo(byte[] bytes, int offset, int len) {

        if (len < 13) {
            return 1;
        } else {
            /*byte转为long比较*/
            /*long timeTarget = Long.parseLong(new String(data));
            long timeInDB = Long.parseLong(new String(bytes, skip + offset, 13));

            if (timeTarget < timeInDB) {
                return -1;
            } else if (timeTarget == timeInDB) {
                return 0;
            } else {
                return 1;
            }*/

            for (int i = 0; i < data.length; i++) {
                byte b1 = data[i];
                byte b2 = bytes[i + offset + skip];
                if (b1 < b2) {
                    return -1;
                } else if (b1 > b2) {
                    return 1;
                }
            }
            return 0;
        }
    }
}

 

按照自己的逻辑实现compareTo方法,比较器的比较逻辑所在。

使用protobuf生成的java类实现toByteArray方法,用于比较器的序列化。

使用protobuf生成的java类实现parseFrom方法,在RegionServer上反序列化使用。

自定义比较器类创建完毕!

 

4、将实现的自定义的比较器打包,放入Hbase的各RegionServer的lib目录下

不然使用自定义比较器会出现ClassNotFound错误。

 

(如有不对,欢迎指正!)

 

---------------------------------补充分割线2019年10月14日----------------------------

如今想来,当初想利用Hbase比较器实现复杂条件的查询的想法,貌似是错误的!

Hbase作为NoSql库,自身拥有高可扩展性,rowkey查询的高性能等特性,而复杂的业务条件,组合查询应该使用外部索引去实现更为妥当!(ES、Solr)