一、过滤器

在上述我们使用get与scan的中可以观察到构造函数的重载中存在一个可传入Filter接口的实现对象,而
该接口则是用于进行更高级的过滤筛选,除了该接口其还提供了一个抽象类 FilterBase ,大部分过滤
器都继承自该抽象类,当然用户自定义开发的过滤器一般也是继承自它。 下面我们将介绍系统本身提供
好的过滤器。

比较运算符

首先我们需要了解的就是可用于过滤器的运算符,其设计采用了基于枚举的方式作为具体过滤器的参数。
考虑到平台的未来兼容性对于 CompareFilter.CompareOp 不在支持,所以需要读者采用 CompareOperator
以保证未来的兼容性,其中枚举为我们提供了如下几种:

  • LESS:匹配小于设定值的值
  • LESS_OR_EQUAL:匹配小于或等于设定值的值
  • EQUAL:匹配等于设定值的值
  • NOT_EQUAL:匹配与设定值不相等的值
  • GREATER_OR_EQUAL:匹配大于或等于设定值的值
  • GREATER:匹配大于设定值的值
  • NO_OP:排除一切值

以上各类运算符需要与实际的比较器进行搭配使用才可以发挥具体的效果。

比较器

讲述完上述的运算符,我们继续讲述比较器,其约束的具体的比较方式,平台提供了如下几种可供
使用的比较器,具体如下所列:

  • BinaryComparator:使用Bytes.compareTo比较当前值与阈值
  • BinaryPrefixComparator:与上面的相似,使用Bytes.compareTo进行匹配,但是是从左端开始前缀匹配
  • NullComparator:不做匹配,只判断当前值是不是null
  • BitComparator:通过BitwiseOp类提供的按位与、或、异或执行位级比较
  • RegexStringComparator:根据一个正则表达式,在实例化这个比较器的时候去匹配表中的数据
  • SubStringComparator:把阈值和表中数据当作String实例,同时通过contains操作匹配字符串

其中需要注意 BitComparatorRegexStringComparatorSubStringComparator 比较器只能与
EQUAL和NOT_EQUAL运算符搭配使用,因为这些比较器的compareTo方法匹配时返回0,不匹配范围1,如
果使用不兼容的运算符会产生错误结果。

同时对于 RegexStringComparatorSubStringComparator 这类比较器,相比字节比较器来说更慢,且
更消耗资源。

比较过滤器

在介绍具体的过滤器前,除了专用与附加过滤器以外,我们常用的均为比较过滤器,其特点就是均继承自 CompareFilter
而该类对应的构造函数如下。

  1. CompareFilter(CompareOperator op, ByteArrayComparable rowComparator)

读者需要了解,过滤器本来的目的是为了筛掉无用的信息。被过滤掉的信息不会被发送到客户端。过滤器不能用来指定
用户需要哪些信息,而是在读取数据的过程中不返回用户不想要的信息。但是所以基于CompareFilter的过滤器正好相反,它
返回匹配的值。

1. 行过滤器

该过滤器将行键作为值根据我们的运算符与比较器进行对比,并返回符合要求的值,具体使用方式如下:

  1. Scan scan = new Scan();
  2. scan.addColumn(Bytes.toBytes("mycf"), Bytes.toBytes("qual1"));
  3. Filter filter1 = new RowFilter(CompareOperator.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("row22")));
  4. scan.setFilter(filter1);
  5. ResultScanner scanner1 = table.getScanner(scan);
  6. for (Result result : scanner1) {
  7. System.out.println(result);
  8. }
  9. scanner1.close();
  10. Filter filter2 = new RowFilter(CompareOperator.EQUAL, new RegexStringComparator(".*2"));
  11. scan.setFilter(filter2);
  12. ResultScanner scanner2 = table.getScanner(scan);
  13. for (Result result : scanner2) {
  14. System.out.println(result);
  15. }
  16. scanner2.close();

2. 列簇过滤器

顾名思义,该过滤器与行过滤器一样,只是是通过列簇来进行判断,具体的使用方式如下:

  1. Scan scan = new Scan();
  2. Filter filter1 = new FamilyFilter(CompareOperator.LESS, new BinaryComparator(Bytes.toBytes("mycf2")));
  3. scan.setFilter(filter1);
  4. ResultScanner resultScanner = table.getScanner(scan);
  5. for (Result result : resultScanner) {
  6. System.out.println(result);
  7. }
  8. Get get1 = new Get(Bytes.toBytes("row1"));
  9. get1.setFilter(filter1);
  10. Result result = table.get(get1);
  11. System.out.println(result);

3. 列名过滤器

接着就是根据列名进行过滤,具体的使用方式如下:

  1. Scan scan = new Scan();
  2. Filter filter = new QualifierFilter(CompareOperator.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("qual2")));
  3. scan.setFilter(filter);
  4. ResultScanner resultScanner = table.getScanner(scan);
  5. for (Result result : resultScanner) {
  6. System.out.println(result);
  7. }
  8. resultScanner.close();
  9. Get get = new Get(Bytes.toBytes("row2"));
  10. get.setFilter(filter);
  11. Result result = table.get(get);
  12. System.out.println(result);

4. 值过滤器

讲述完根据各类名称进行过滤,对于我们来说会经常使用的可能就是值过滤器,具体的使用方式如下:

  1. Filter filter = new ValueFilter(CompareOperator.EQUAL, new SubstringComparator("1"));
  2. Scan scan = new Scan();
  3. scan.setFilter(filter);
  4. ResultScanner scanner = table.getScanner(scan);
  5. for (Result result : scanner) {
  6. for (Cell c : result.rawCells()) {
  7. System.out.println("q: " + Bytes.toString(c.getQualifierArray()) + " v: " + Bytes.toString(c.getValueArray()));
  8. }
  9. }
  10. scanner.close();
  11. Get get = new Get(Bytes.toBytes("row1"));
  12. get.setFilter(filter);
  13. Result result = table.get(get);
  14. for (Cell c : result.rawCells()) {
  15. System.out.println("q: " + Bytes.toString(c.getQualifierArray()) + " v: " + Bytes.toString(c.getValueArray()));
  16. }

5. 单列值过滤器

其作用就是用一列的值决定是否一行数据被过滤( SingleColumnValueExcludeFilter 起到相反作用)。首先需要设定待检查的列,然后设置待检查的列的对应值,比如如下用法:

  1. SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("mycf"), Bytes.toBytes("qual1"), CompareOperator.EQUAL, new SubstringComparator("1"));
  2. filter.setFilterIfMissing(true);
  3. Scan scan = new Scan();
  4. scan.setFilter(filter);
  5. ResultScanner scanner = table.getScanner(scan);
  6. for (Result result : scanner) {
  7. System.out.println(result);
  8. }
  9. scanner.close();
  10. Get get = new Get(Bytes.toBytes("row1"));
  11. get.setFilter(filter);
  12. Result result = table.get(get);
  13. System.out.println(result);

其中我们可以看到 setFilterIfMissing 函数的调用,其决定了当参考列不存在时如何处理这一行。默认情况下这一行是被
包含在结果中的,如果设置为true将过滤这些行。

6. 前缀过滤器

采用行键的前缀匹配方式进行匹配,具体使用方式如下:

  1. Filter filter = new PrefixFilter(Bytes.toBytes("row"));
  2. Scan scan = new Scan();
  3. scan.setFilter(filter);
  4. ResultScanner scanner = table.getScanner(scan);
  5. for (Result result : scanner) {
  6. System.out.println(result);
  7. }
  8. scanner.close();
  9. Get get = new Get(Bytes.toBytes("row1"));
  10. get.setFilter(filter);
  11. Result result = table.get(get);
  12. System.out.println(result);

对应列名称则可以通过 ColumnPrefixFilter 过滤器进行过滤。

7. 分页过滤器

这个过滤器对结果按行分页,需要注意在物理上分离的服务器中并行执行过滤操作时,需要注意以下几个事项,在不同的Region
服务器上并行执行的过滤器不能共享他们现在的状态和边界,因此,每个过滤器都会在完成扫描前获取pageCount行的结果,这
种情况使得分页过滤器可能失效,极有可能返回的比所需要的多,最终客户端在合并结果时可以选择返回所有的结果。

  1. Filter filter = new PageFilter(15);
  2. Scan scan = new Scan();
  3. scan.setFilter(filter);
  4. scan.withStartRow(Bytes.toBytes("row1"));
  5. ResultScanner scanner = table.getScanner(scan);
  6. for (Result result : scanner) {
  7. System.out.println(result);
  8. }
  9. scanner.close();

8. 行键过滤器

对于只需要结果中将Cell实例中的键返回,而不需要返回实际的数据。KeyOnlyFilter提供了可以修改扫描出的单元格的功能。这个
过滤器通过其构造函数的lenAsVal的布尔参数,这个参数默认为false,代表不获取对应的值,反之值则设为原值长度的字节数组。

9. 首次行键过滤器

如果读者需要访问一行中的第一例,则这种过滤器可以满足需求。这种过滤器通常在行数统计的应用场景中使用,这种场景
只需要检查这一行是否存在。在列式存储数据库中如果某一行存在,则行中必然有列。

10. 包含结束的过滤器

扫描操作中的开始行被包含到结果中,但终止行被排除在外。使用这个过滤器时,用户也可以将结束行包括到结果中。具体
使用方式如下。

  1. Filter filter = new InclusiveStopFilter(Bytes.toBytes("row3"));
  2. Scan scan = new Scan();
  3. scan.setFilter(filter);
  4. scan.withStartRow(Bytes.toBytes("row1"));
  5. ResultScanner scanner = table.getScanner(scan);
  6. for (Result result : scanner) {
  7. System.out.println(result);
  8. }
  9. scanner.close();

11. 时间戳过滤器

如果读者需要根据数据的版本进行过滤,就可以使用该过滤器进行过滤。该过滤器可以传入多个版本进行过滤。具体使用
方式如下。

  1. List<Long> ts = new ArrayList<>();
  2. ts.add(5l);
  3. ts.add(10l);
  4. ts.add(15l);
  5. Filter filter = new TimestampsFilter(ts);
  6. Scan scan = new Scan();
  7. scan.setFilter(filter);
  8. ResultScanner scanner = table.getScanner(scan);
  9. for (Result result : scanner) {
  10. System.out.println(result);
  11. }
  12. scanner.close();

12. 列计数过滤器

考虑到HBase的设计,一行数据可能会存在多个列数据,如果读者需要仅返回前面几个列即可,那么就适合使用上述的过滤器进行过
滤。

13. 列分页过滤器

PageFilter相似,只是该过滤器用于对一行的所有列进行分页,具体使用方式如下。

  1. Filter filter = new ColumnPaginationFilter(1, 1);
  2. Scan scan = new Scan();
  3. scan.setFilter(filter);
  4. ResultScanner scanner = table.getScanner(scan);
  5. for (Result result : scanner) {
  6. System.out.println(result);
  7. }
  8. scanner.close();

14. 跳转过滤器

由于上述的过滤器均会按照其范围过滤对应范围的值,如值过滤器将会过滤不符合要求的值单元格,而不是过滤掉该行。所以
读者如果需要根据其列值确定是否过滤掉该行,那么就需要组合值过滤器与本节过滤器进行过滤即可。

  1. Filter filter = new ValueFilter(CompareOperator.NOT_EQUAL, new BinaryComparator(Bytes.toBytes("val")));
  2. Filter filter2 = new SkipFilter(filter);
  3. Scan scan = new Scan();
  4. scan.setFilter(filter2);
  5. ResultScanner scanner = table.getScanner(scan);
  6. for (Result result : scanner) {
  7. System.out.println(result);
  8. }
  9. scanner.close();

根据上述的过滤器逻辑,还有一种叫全匹配过滤器。其将会在遇到不符合要求的数据后直接放弃本次扫描操作,其过滤器为 WhileMatchFilter

15. 多过滤器

实际研发过程中往往我们需要组合多种过滤器来满足我们的需求,本节我们将介绍如何使用,首先我们需要了解其构造函数为
我们提供了两种方式。

FilterList(List<Filter> rowFilters);
FilterList(Operator operator);
FilterList(Operator operator, List<Filter> rowFilters);

其中我们可以发现 Operator 枚举类,其默认为 MUST_PASS_ALL 即数据满足所有过滤器才放入结果集中,反之我们可以
使用 MUST_PASS_ONE 要求仅满足众多过滤器中的一个即可。下面我们使用其进行过滤。

List<Filter> filters = new ArrayList<>();

Filter filter1 = new ValueFilter(CompareOperator.NOT_EQUAL, new BinaryComparator(Bytes.toBytes("val")));
filters.add(filter1);

Filter filter2 = new ColumnPaginationFilter(1, 1);
filters.add(filter2);

FilterList filterList = new FilterList(filters);
Scan scan = new Scan();
scan.setFilter(filterList);
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
    System.out.println(result);
}
scanner.close();

上述我们介绍了HBase自带的各类过滤器,关于自定义过滤器我们将另起篇幅进行编写