使用hbase最关心与主要的问题就是过滤条件、排序、分页问题,下面是一些常用到的相关方法。其中做的分页不是很理想,所以就一笔带过了。
1 相关组件
1.1 Phoenix
类似sql的工具,需要添加几个包,但是不能访问原有的相关表。只能使用sqlline进行创建表。
2 Hbase API高级特性-专用过滤器
1.
Hbase提供的专用过滤器直接继承自FilterBase,其中一些过滤器只能做行筛选,因此只适合于扫描操作,对get(),这些过滤器限制的更苛刻:要么包含整行,要么什么都不包括。
2.1 单列值过滤器(SingleColumnValueFilter)
用一列的值决定是否一行数据被过滤。
public void singleColumnValueFilter() throws IOException{
SingleColumnValueFilter filter = newSingleColumnValueFilter(Bytes.toBytes("info"),
Bytes.toBytes("name"), CompareFilter.CompareOp.LESS_OR_EQUAL,
new BinaryComparator(Bytes.toBytes("ljj")));
filter.setFilterIfMissing(true); //所有不包含参考列的行都可以被过滤掉,默认这一行包含在结果中
Scan scan = new Scan();
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for(Result res:scanner){
for(KeyValue kv: res.raw()){
System.out.println("KV: "+kv + ",value: "+Bytes.toString(kv.getValue()));
}
}
scanner.close();
Get get = new Get(Bytes.toBytes("3103"));
get.setFilter(filter);
Result result = table.get(get);
System.out.println("Result of get(): " + result);
for(KeyValue kv:result.raw()){
System.out.println("KV: "+kv + ",value:"+Bytes.toString(kv.getValue()));
}
}
2.2 单列排除过滤器(SingleColumnValueExcludeFilter)
该过滤器继承SingleColumnValueFilter,参考列不会包含在结果中。
2.3 前缀过滤器(PrefixFilter)
所用与前缀匹配的行都会被返回。扫描操作以字典序查找,当遇到比前缀大的行时,扫描结束。此过滤器对get()方法作用不大。
public void prefixFilter() throws IOException{
Filter filter = new PrefixFilter(Bytes.toBytes("31"));
Scan scan = new Scan();
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for(Result res:scanner){
for(KeyValue kv: res.raw()){
System.out.println("KV: "+kv + ",value: "+Bytes.toString(kv.getValue()));
}
}
scanner.close();
//此过滤器对get()方法作用不大
}
2.4 分页过滤器(PageFilter)
作用:对结果按行分页。
public void pageFilter() throws IOException{
Filter filter = new PageFilter(4);
int totalRows = 0;
byte[] lastRow = null;
byte[] POSTFIX = new byte[0];
while(true){
Scan scan = new Scan();
scan.setFilter(filter);
if(lastRow != null){
byte[] startRow = Bytes.add(lastRow, POSTFIX);
System.out.println("start row: "+Bytes.toString(startRow));
scan.setStartRow(startRow);
}
ResultScanner scanner = table.getScanner(scan);
int localRows = 0;
Result result;
while((result = scanner.next()) != null){
System.out.println(localRows++ +": "+result);
totalRows++;
lastRow = result.getRow();
}
scanner.close();
if(localRows == 0)
break;
}
System.out.println("total rows: "+ totalRows);
}
2.5 行键过滤器(KeyOnlyFilter)
只需要将结果中KeyValue实例的键返回,不需要返回实际的数据。
2.6 首次行键过滤器(FirstKeyOnlyFilter)
只需要访问一行中的第一列。该过滤器常用在行数统计。
2.7 包含结束的过滤器(InclusiveStopFilter)
开始行被包含在结果中,但终止行被排斥在外,使用这个过滤器,也可以将结束行包含在结果中。
public void inclusiveStopFilter() throws IOException{
Filter filter = new InclusiveStopFilter(Bytes.toBytes("3104"));
Scan scan = new Scan();
scan.setStartRow(Bytes.toBytes("3101"));
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for(Result res: scanner){
System.out.println(res);
}
}
2.8 时间戳过滤器(TimestampsFilter)
需要在扫描结果中对版本进行细粒度控制。
一个版本是指一个列在一个特定时间的值。
public void timestampsFilter() throws IOException{
List<Long> ts = new ArrayList<Long>();
ts.add(new Long(5));
ts.add(new Long(10));
ts.add(new Long(15));
Filter filter = new TimestampsFilter(ts);
Scan scan = new Scan();
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for(Result res:scanner){
System.out.println(res);
}
scanner.close();
Scan scan2 = new Scan();
scan2.setFilter(filter);
scan2.setTimeRange(8, 12);
ResultScanner scanner2 = table.getScanner(scan2);
for(Result res:scanner2)
System.out.println(res);
scanner2.close();
}
2.9 列计数过滤器(ColumnCountGetFilter)
限制每行最多取回多少列。设置ColumnCountGetFilter(int n),它不适合扫描操作,更适合get()。
2.10 列分页过滤器(ColumnPaginationFilter)
可以对一行中所有列进行分页。
ColumnPaginationFilter(intlimit,int offset),跳过所有偏移量小于offset的列,并包含之前所有偏移量在limit之前的列。
public void columnPaginationFilter() throws IOException{
Filter filter = new ColumnPaginationFilter(2,3);
Scan scan = new Scan();
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for(Result res:scanner)
System.out.println(res);
scanner.close();
}
2.11 列前缀过滤器(ColumnPrefixFilter)
对列名称前缀进行匹配。
2.12 随机行过滤器(RandomRowFilter)
可以让结果中包含随机行。RandomRowFilter(float chance)
Chance在0~1之间。
3 过滤器2
HBase为筛选数据提供了一组过滤器,通过这个过滤器可以在HBase中的数据的多个维度(行,列,数据版本)上进行对数据的筛选操作,也就是说过滤器最终能够筛选的数据能够细化到具体的一个存储单元格上(由行键,列明,时间戳定位)。通常来说,通过行键,值来筛选数据的应用场景较多。
1. RowFilter:筛选出匹配的所有的行,对于这个过滤器的应用场景,是非常直观的:使用BinaryComparator可以筛选出具有某个行键的 行,或者通过改变比较运算符(下面的例子中是CompareFilter.CompareOp.EQUAL)来筛选出符合某一条件的多条数据,以下就是筛 选出行键为row1的一行数据:
[java] view plain copy
- Filter rf = new RowFilter(CompareFilter.CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("row1"))); // OK 筛选出匹配的所有的行
2. PrefixFilter:筛选出具有特定前缀的行键的数据。这个过滤器所实现的功能其实也可以由RowFilter结合RegexComparator来实现,不过这里提供了一种简便的使用方法,以下过滤器就是筛选出行键以row为前缀的所有的行:
[java] view plain copy
- Filter pf = new PrefixFilter(Bytes.toBytes("row")); // OK 筛选匹配行键的前缀成功的行
3. KeyOnlyFilter:这个过滤器唯一的功能就是只返回每行的行键,值全部为空,这对于只关注于行键的应用场景来说非常合适,这样忽略掉其值就可以减少传递到客户端的数据量,能起到一定的优化作用:
[java] view plain copy
- Filter kof = new KeyOnlyFilter(); // OK 返回所有的行,但值全是空
4. RandomRowFilter:从名字上就可以看出其大概的用法,本过滤器的作用就是按照一定的几率(<=0会过滤掉所有的行,& gt;=1会包含所有的行)来返回随机的结果集,对于同样的数据集,多次使用同一个RandomRowFilter会返回不通的结果集,对于需要随机抽取 一部分数据的应用场景,可以使用此过滤器:
[java] view plain copy
- Filter rrf = new RandomRowFilter((float) 0.8); // OK 随机选出一部分的行
5. InclusiveStopFilter:扫描的时候,我们可以设置一个开始行键和一个终止行键,默认情况下,这个行键的返回是前闭后开区间,即包含起始行,单不包含中指行,如果我们想要同时包含起始行和终止行,那么我们可以使用此过滤器:
[java] view plain copy
- Filter isf = new InclusiveStopFilter(Bytes.toBytes("row1")); // OK 包含了扫描的上限在结果之内
6. FirstKeyOnlyFilter:如果你只想返回的结果集中只包含第一列的数据,那么这个过滤器能够满足你的要求。它在找到每行的第一列之后会停止扫描,从而使扫描的性能也得到了一定的提升:
[java] view plain copy
- Filter fkof = new FirstKeyOnlyFilter(); // OK 筛选出第一个每个第一个单元格
7. ColumnPrefixFilter:顾名思义,它是按照列名的前缀来筛选单元格的,如果我们想要对返回的列的前缀加以限制的话,可以使用这个过滤器:
[java] view plain copy
- Filter cpf = new ColumnPrefixFilter(Bytes.toBytes("qual1")); // OK 筛选出前缀匹配的列
8. ValueFilter:按照具体的值来筛选单元格的过滤器,这会把一行中值不能满足的单元格过滤掉,如下面的构造器,对于每一行的一个列,如果其对应的值不包含ROW2_QUAL1,那么这个列就不会返回给客户端:
[java] view plain copy
- Filter vf = new ValueFilter(CompareFilter.CompareOp.EQUAL, new SubstringComparator("ROW2_QUAL1")); // OK 筛选某个(值的条件满足的)特定的单元格
9. ColumnCountGetFilter:这个过滤器来返回每行最多返回多少列,并在遇到一行的列数超过我们所设置的限制值的时候,结束扫描操作:
[java] view plain copy
- Filter ccf = new ColumnCountGetFilter(2); // OK 如果突然发现一行中的列数超过设定的最大值时,整个扫描操作会停止
10. SingleColumnValueFilter:用一列的值决定这一行的数据是否被过滤。在它的具体对象上,可以调用 setFilterIfMissing(true)或者setFilterIfMissing(false),默认的值是false,其作用是,对于咱们 要使用作为条件的列,如果这一列本身就不存在,那么如果为true,这样的行将会被过滤掉,如果为false,这样的行会包含在结果集中。
[java] view plain copy
- SingleColumnValueFilter scvf = new SingleColumnValueFilter(
- Bytes.toBytes("colfam1"),
- Bytes.toBytes("qual2"),
- CompareFilter.CompareOp.NOT_EQUAL,
- new SubstringComparator("BOGUS"));
- scvf.setFilterIfMissing(false);
- scvf.setLatestVersionOnly(true); // OK
11. SingleColumnValueExcludeFilter:这个与10种的过滤器唯一的区别就是,作为筛选条件的列的不会包含在返回的结果中。
12. SkipFilter:这是一种附加过滤器,其与ValueFilter结合使用,如果发现一行中的某一列不符合条件,那么整行就会被过滤掉:
[java] view plain copy
- Filter skf = new SkipFilter(vf); // OK 发现某一行中的一列需要过滤时,整个行就会被过滤掉
13. WhileMatchFilter:这个过滤器的应用场景也很简单,如果你想要在遇到某种条件数据之前的数据时,就可以使用这个过滤器;当遇到不符合设定条件的数据的时候,整个扫描也就结束了:
[java] view plain copy
- Filter wmf = new WhileMatchFilter(rf); // OK 类似于Python itertools中的takewhile
14. FilterList:用于综合使用多个过滤器。其有两种关系:FilterList.Operator.MUST_PASS_ONE和FilterList.Operator.MUST_PASS_ALL,默认的是FilterList.Operator.MUST_PASS_ALL,顾名思义,它们分别是AND和OR的关系,并且FilterList可以嵌套使用FilterList,使我们能够表达更多的需求:
[java] view plain copy
- List<Filter> filters = new ArrayList<Filter>();
- filters.add(rf);
- filters.add(vf);
- FilterList fl = new FilterList(FilterList.Operator.MUST_PASS_ALL, filters); // OK 综合使用多个过滤器, AND 和 OR 两种关系
以上,是对于HBase内置的过滤器的部分总结,以下代码是数据写入代码:
[java] view plain copy
- package com.reyun.hbase;
- import java.io.IOException;
- import org.apache.hadoop.conf.Configuration;
- import org.apache.hadoop.hbase.HBaseConfiguration;
- import org.apache.hadoop.hbase.client.HTable;
- import org.apache.hadoop.hbase.client.Put;
- import org.apache.hadoop.hbase.util.Bytes;
- public class HBaseDataFeeding {
- private final static byte[] ROW1 = Bytes.toBytes("row1");
- private final static byte[] ROW2 = Bytes.toBytes("row2");
- private final static byte[] COLFAM1 = Bytes.toBytes("colfam1");
- private final static byte[] COLFAM2 = Bytes.toBytes("colfam2");
- private final static byte[] QUAL1 = Bytes.toBytes("qual1");
- private final static byte[] QUAL2 = Bytes.toBytes("qual2");
- public static void main(String[] args) throws IOException {
- Configuration conf = HBaseConfiguration.create();
- HTable table = new HTable(conf, "testtable");
- table.setAutoFlushTo(false);
- Put put_row1 = new Put(ROW1);
- put_row1.add(COLFAM1, QUAL1, Bytes.toBytes("ROW1_QUAL1_VAL"));
- put_row1.add(COLFAM1, QUAL2, Bytes.toBytes("ROW1_QUAL2_VAL"));
- Put put_row2 = new Put(ROW2);
- put_row2.add(COLFAM1, QUAL1, Bytes.toBytes("ROW2_QUAL1_VAL"));
- put_row2.add(COLFAM1, QUAL2, Bytes.toBytes("ROW2_QUAL2_VAL"));
- try{
- table.put(put_row1);
- table.put(put_row2);
- }finally{
- table.close();
- }
- }
- }
以下是过滤器测试代码,可以通过修改代码,更换过滤器来看到具体的效果:
[java] view plain copy
- package com.reyun.hbase;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import org.apache.hadoop.conf.Configuration;
- import org.apache.hadoop.hbase.Cell;
- import org.apache.hadoop.hbase.CellUtil;
- import org.apache.hadoop.hbase.HBaseConfiguration;
- import org.apache.hadoop.hbase.client.HTable;
- import org.apache.hadoop.hbase.client.Result;
- import org.apache.hadoop.hbase.client.ResultScanner;
- import org.apache.hadoop.hbase.client.Scan;
- import org.apache.hadoop.hbase.filter.BinaryComparator;
- import org.apache.hadoop.hbase.filter.ColumnCountGetFilter;
- import org.apache.hadoop.hbase.filter.ColumnPrefixFilter;
- import org.apache.hadoop.hbase.filter.CompareFilter;
- import org.apache.hadoop.hbase.filter.Filter;
- import org.apache.hadoop.hbase.filter.FilterList;
- import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
- import org.apache.hadoop.hbase.filter.InclusiveStopFilter;
- import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
- import org.apache.hadoop.hbase.filter.PageFilter;
- import org.apache.hadoop.hbase.filter.PrefixFilter;
- import org.apache.hadoop.hbase.filter.RandomRowFilter;
- import org.apache.hadoop.hbase.filter.RowFilter;
- import org.apache.hadoop.hbase.filter.SkipFilter;
- import org.apache.hadoop.hbase.filter.ValueFilter;
- import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
- import org.apache.hadoop.hbase.filter.SubstringComparator;
- import org.apache.hadoop.hbase.filter.WhileMatchFilter;
- import org.apache.hadoop.hbase.util.Bytes;
- public class HBaseScannerTest {
- public static void main(String[] args) throws IOException, IllegalAccessException {
- Configuration conf = HBaseConfiguration.create();
- HTable table = new HTable(conf, "testtable");
- table.setAutoFlushTo(false);
- Scan scan1 = new Scan();
- SingleColumnValueFilter scvf = new SingleColumnValueFilter(
- Bytes.toBytes("colfam1"),
- Bytes.toBytes("qual2"),
- CompareFilter.CompareOp.NOT_EQUAL,
- new SubstringComparator("BOGUS"));
- scvf.setFilterIfMissing(false);
- scvf.setLatestVersionOnly(true); // OK
- Filter ccf = new ColumnCountGetFilter(2); // OK 如果突然发现一行中的列数超过设定的最大值时,整个扫描操作会停止
- Filter vf = new ValueFilter(CompareFilter.CompareOp.EQUAL, new SubstringComparator("ROW2_QUAL1")); // OK 筛选某个(值的条件满足的)特定的单元格
- Filter cpf = new ColumnPrefixFilter(Bytes.toBytes("qual2")); // OK 筛选出前缀匹配的列
- Filter fkof = new FirstKeyOnlyFilter(); // OK 筛选出第一个每个第一个单元格
- Filter isf = new InclusiveStopFilter(Bytes.toBytes("row1")); // OK 包含了扫描的上限在结果之内
- Filter rrf = new RandomRowFilter((float) 0.8); // OK 随机选出一部分的行
- Filter kof = new KeyOnlyFilter(); // OK 返回所有的行,但值全是空
- Filter pf = new PrefixFilter(Bytes.toBytes("row")); // OK 筛选匹配行键的前缀成功的行
- Filter rf = new RowFilter(CompareFilter.CompareOp.NOT_EQUAL, new BinaryComparator(Bytes.toBytes("row1"))); // OK 筛选出匹配的所有的行
- Filter wmf = new WhileMatchFilter(rf); // OK 类似于Python itertools中的takewhile
- Filter skf = new SkipFilter(vf); // OK 发现某一行中的一列需要过滤时,整个行就会被过滤掉
- List<Filter> filters = new ArrayList<Filter>();
- filters.add(rf);
- filters.add(vf);
- FilterList fl = new FilterList(FilterList.Operator.MUST_PASS_ALL, filters); // OK 综合使用多个过滤器, AND 和 OR 两种关系
- scan1.
- setStartRow(Bytes.toBytes("row1")).
- setStopRow(Bytes.toBytes("row3")).
- setFilter(scvf);
- ResultScanner scanner1 = table.getScanner(scan1);
- for(Result res : scanner1){
- for(Cell cell : res.rawCells()){
- System.out.println("KV: " + cell + ", Value: " + Bytes.toString(CellUtil.cloneValue(cell)));
- }
- System.out.println("------------------------------------------------------------");
- }
- scanner1.close();
- table.close();
- }
- }
4 全局COPROCESSOR配置
1.启动全局aggregation,能过操纵所有的表上的数据。通过修改hbase-site.xml这个文件来实现,只需要添加如下代码:
<property>
<name>hbase.coprocessor.user.region.classes</name>
<value>org.apache.hadoop.hbase.coprocessor.AggregateImplementation</value>
</property>
5 倒序查询
sc.setReversed(true);
6 分页查询及带上检索条件
1、 首先确定当前请求的类型【第一页,上一页,下一页,最后一页,检索,修改,删除】;
2、 如果当前操作为【第一页、检索】,那么设置PAGE为初始,并且使用condtion进行过滤
7 复杂查询过滤
在上面查询比较简单,但实际业务中经常遇到更复杂的查询。例如:where (A like ? and B=?)or(where A like ? Or B=?),与上面示例相比,其实是多了一层嵌套。
在HBase中我们也可以嵌套FilterList来实现这种复杂的查询:
FilterList andlist = new FilterList(Operator.MUST_PASS_ALL);
andlist.addFilter(FilterHelper.getRegexStringFilter(field_A, field_A_Value));
andlist.addFilter(FilterHelper.getEqualFilter(field_B, field_A_Value));
FilterList orlist = new FilterList(Operator.MUST_PASS_ONE);
orlist.addFilter(FilterHelper.getRegexStringFilter(field_A, field_A_Value));
orlist.addFilter(FilterHelper.getEqualFilter(field_B, field_A_Value));
FilterList list = new FilterList(Operator.MUST_PASS_ONE);
list.addFilter(andlist);
list.addFilter(orlist);