hbase有两种查询的方式一个get 一个scan
其中get是根据精确的rowkey查出单条的记录 ,那么如果一条记录是有成千上万个字段的话,网络IO大,所以要
get.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("f3"));
get.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("f2"));
来添加和指定要返回的字段
还有一种方式是get.setFilter(filter) ,这个我没试过
scan 自然也有按照filter来筛选出要返回的字段
filter是这样,客户端可以把filter发送到各个regionserver中,做到在服务端去过滤,从而减少网络IO,而不是说一个简单的scan把所有符合rowkey的都返回给客户端,由客户端来做过滤处理。
如果是get的filter只能做针对列的过滤的话
scan的filter既有针对rowkey的过滤也有针对列的过滤,从而形成一个行列的聚焦。
针对rowkey的filter 用的最多的是前缀过滤
PrefixFilter prefixFilter = new PrefixFilter(Bytes.toBytes("01_1893300"));
这里要多说一句,这里前缀实际的所用是包含 也就是说 01_1893300_aa 和 aa_01_1893300 都是符合前缀过滤的
针对列过滤的我这里常用的是列名的filter ,如果要返回多个列的话
QualifierFilter qualifierFilter1 = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("f1")));
QualifierFilter qualifierFilter2 = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("f2")));
当scan既要对行也要对列进行同时过滤时,要用filterList来整合
但这时要注意,filterLIst只能用来整合列的,不要把列过滤和行过滤都一起整合到filterLIst
例如这里就是
//先创建一个scan
Scan scan = new Scan();
//创建了一个rowkey前缀过滤
PrefixFilter prefixFilter = new PrefixFilter(Bytes.toBytes("01_1893300"));
//直接把filter设置到scan中(单独设置)
scan.setFilter(prefixFilter);
//创建一个fliterList (Operator.MUST_PASS_ONE,Operator.MUST_PASS_ALL)
FilterList filterList = new FilterList(Operator.MUST_PASS_ONE); //要是两个列都含有的话,一定要设置为ONE
//创建两个列过滤
QualifierFilter qualifierFilter1 = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("f1")));
QualifierFilter qualifierFilter2 = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("f2")));
//把两个列过滤放到filterLIst中而不要把rowkey行过滤放入
filterList.addFilter(qualifierFilter1);
filterList.addFilter(qualifierFilter2);
//把这个filterList设置到scan中
scan.setFilter(filterList);
这样才会过滤下来你指定的行 和 指定的列的值,其他的都不会通过网络传到客户端了
另外hbase是设计成按照rowkey来查询才能最大化查询效率的,我没有用过二级索引,所以就不说这个了
那么如果单通过列值来过滤话就会效果很差
还有如果通过filter查到了也就罢了,如果filter后查不到,响应速度就会很慢,会有十几秒
所以当用filter时要加个判断
if (result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("f2")) != null) {
System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("cf"),Bytes.toBytes("f2"))));
}
那么分别给个get 和 scan 的带过滤的查询的列子
// Table table = HbaseUtils.getHTable();
// Get get = new Get(Bytes.toBytes("01_1893300_aa"));
get.setFilter(filter)
//
// get.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("f3"));
// get.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("f2"));
//
// Result result = table.get(get);
//
// System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("f1")))); // result.getRow() 是获得rowkey
//-------------------------
Table table = HbaseUtils.getHTable();
Scan scan = new Scan();
FilterList filterList = new FilterList(Operator.MUST_PASS_ONE);
PrefixFilter prefixFilter = new PrefixFilter(Bytes.toBytes("01_1893300")); //前缀的话 ,其实不在前缀也是可以的
QualifierFilter qualifierFilter1 = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("f1")));
QualifierFilter qualifierFilter2 = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("f2")));
filterList.addFilter(qualifierFilter1);
filterList.addFilter(qualifierFilter2);
scan.setFilter(prefixFilter);
scan.setFilter(filterList);
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 判断取出来的值是否为空
if (result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("f2")) != null) {
System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("cf"),Bytes.toBytes("f2"))));
}
// 判断取出来的值是否为空
if (result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("f3")) != null) {
System.out.println(Bytes.toString(result.getValue(Bytes.toBytes("cf"),Bytes.toBytes("f3"))));
}
}
最后多说一句 以手机号为例 183**********
如果hbase的业务偏向查询的话,那手机号最好正写,当批量查询是会从同一个region出,效率高
如果hbase的业务偏向插入的话,那手机号最好反写,当批量插入的时候,写时分布平衡
参考
http://www.cnblogs.com/kxdblog/p/4328699.html
http://www.cnblogs.com/skyl/p/4807793.html