hbase查询时内置功能较弱,如果需要自定义查询,则需要开发自定义的比较器。
hbase自定义查询原理是将我们自定义的java比较器通过rpc方式传给hbase服务器来执行,所以涉及到比较器代码的序列化反序列化过程。hbase使用的是google的protocal buf这个工具。
步骤如下:
1 下载protocolbuffers windows版
https://github.com/protocolbuffers/protobuf/releases/tag/v3.6.1
下载后解压
2 将protoc.exe安装到本地到maven仓库
在命令行执行 mvn install:install-file -DgroupId=io.grpc -DartifactId=protoc-gen-grpc-java -Dversion=3.6.1 -Dclassifier=windows-x86_64 -Dpackaging=exe -Dfile=D:\dev\protoc-3.6.1-win32\bin\protoc.exe
3 在intelij idea开发工具中,配置proto的支持
方式2: 直接命令行执行:
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/MyCompartor.proto
实际使用中发现,方式1虽然高级,但是maven package总有问题,protobuf生成的源代码在target目录下,src下的java无法引用,而且pom.xml需要配置的项目较多。
采用方式2生成更为便捷,直接将生成的代码输出到源码工程的src目录下即可。
4、根据生成的代码书写自己的比较器,需要重载方法:
compareTo:具体执行比较的逻辑
toByteArray:当前类的属性序列化为byte数组的方法
parseFrom:从byte数组反序列化得到当前类实例的方法 下面是我实现的比较器,作用是根据rowkey的子串进行范围匹配比较,子串的start,end位置可以配置。如果rowkey的某个(start,end)之间的子字符串的值在(rangeStart,rangeEnd)范围内则匹配成功。
/**
* 子字符串比较器
*/
public class SubstringRangeComparable extends ByteArrayComparable {
private int start, end;
private String rangeStart;
private String rangeEnd;
/**
*
* @param rangeStart 子字符串的最小值
* @param rangeEnd 子字符串的最大值
* @param start 子字符串在rowkey中的起始index
* @param end 子字符串在rowkey中的结束index
*/
public SubstringRangeComparable(String rangeStart, String rangeEnd, int start, int end) {
super(Bytes.toBytes(rangeStart + "#" + rangeEnd + "#" + start + "#" + end));
this.rangeStart = rangeStart;
this.rangeEnd = rangeEnd;
this.start = start;
this.end = end;
}
@Override
public byte[] getValue() {
return Bytes.toBytes(rangeStart + "#" + rangeEnd + "#" + start + "#" + end);
}
@Override
public int compareTo(byte[] value, int offset, int length) {
String fullstr = Bytes.toString(value, offset, length);
if (fullstr.length() < end) {
return -1;
}
String substr = fullstr.substring(start, end);
boolean inRange = substr.compareTo(rangeStart) >= 0 && substr.compareTo(rangeEnd) <= 0;
return inRange ? 0 : 1;
}
@Override
public byte[] toByteArray() {
SubstringRangeProtos.SubstringRangeComparable.Builder builder =
SubstringRangeProtos.SubstringRangeComparable.newBuilder();
builder.setRangeStart(rangeStart);
builder.setRangeEnd(rangeEnd);
builder.setStart(start);
builder.setEnd(end);
return builder.build().toByteArray();
}
public static SubstringRangeComparable parseFrom(final byte[] pbBytes)
throws DeserializationException {
SubstringRangeProtos.SubstringRangeComparable proto;
try {
proto = SubstringRangeProtos.SubstringRangeComparable.parseFrom(pbBytes);
} catch (InvalidProtocolBufferException e) {
System.err.println("InvalidProtocolBufferException happened.");
e.printStackTrace();
throw new DeserializationException(e);
}
return new SubstringRangeComparable(proto.getRangeStart(), proto.getRangeEnd(), proto.getStart(), proto.getEnd());
}
}
自定义比较器建议专门做个工程开发,完成后打包成jar,发布到hbase的 /lib目录下,重启hbase即可,否则运行时会提示ClassNotFoundException。