HBase 的基本 API,包括增、删、改、查等。查询可以根据 Rowkey 进行 Get 或根据 Rowkey 的范围进行 Scan 扫描。同时提供了更加高级的过滤器(Filter)在 Server 端过滤查询结果,只将满足条件的数据返回给客户端。
过滤器的类型很多,可以分为两大类:比较过滤器和专用过滤器。
比较运算符和比较器
比较过滤器需要两个参数:比较运算符和比较器
比较运算符
在比较过滤器中需要用到比较运算符,HBase 内置以下7种比较运算符
public enum CompareOp {
LESS, // 检查是否小于比较器里的值
LESS_OR_EQUAL, // 检查是否小于或等于比较器里的值
EQUAL, // 检查是否等于比较器里的值
NOT_EQUAL, // 检查是否不等于比较器里的值
GREATER_OR_EQUAL, // 检查是否大于或等于比较器里的值
GREATER, // 检查是否大于比较器里的值
NO_OP, // 默认返回false,因此过滤掉所有的数据
}
比较器
通过比较器可以实现多样化目标匹配效果,比较器有以下子类可以使用:
BinaryComparator // 匹配完整字节数组
BinaryPrefixComparator // 匹配字节数组前缀
BitComparator // 按位执行与、或、异或比较
NullComparator // 判断当前值是不是 NULL
RegexStringComparator // 正则表达式匹配字符串
SubstringComparator // 子串匹配,相当于 contains()
比较过滤器
行键过滤器 RowFilter
Scan scan = new Scan();
Filter filter = new RowFilter(CompareOp.LESS_OR_EQUAL,
new BinaryComparator(Bytes.toBytes("uid-100")));
scan.setFilter(filter);
筛选出匹配的所有的行,基于行键(Rowkey)过滤数据,可以执行精确匹配,子字符串匹配或正则表达式匹配,过滤掉不匹配的数据。
一般来说,对 Rowkey 进行范围过滤,可以执行 Scan 的 startKey 和 endKey,RowFilter 可以更精确的过滤。
列族过滤器 FamilyFilter
Scan scan = new Scan();
Filter filter = new FamilyFilter(CompareFilter.CompareOp.LESS,
new BinaryComparator(Bytes.toBytes("cf-d")));
scan.setFilter(filter);
与 RowFilter 类似,区别是比较列族,而不是比较行键。当 HBase 表有多个列族时,可以用来筛选不同列族中的列。
列名过滤器 QualifierFilter
Scan scan = new Scan();
Filter filter = new QualifierFilter(CompareFilter.CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes("col-1")));
scan.setFilter(filter1);
根据列名进行筛选。
值过滤器 ValueFilter
Scan scan = new Scan();
Filter filter = new ValueFilter(CompareFilter.CompareOp.NOT_EQUAL,
new SubstringComparator("abc"));
scan.setFilter(filter);
筛选特定值的单元格,可以与 RegexStringComparator 搭配使用,完成复杂的筛选。
不同的比较器,只能与部分比较运算符搭配,例如 SubstringComparator 只能使用 EQUAL
或 NOT_EQUAL
参考列过滤器 DependentColumnFilter
Scan scan = new Scan();
Filter filter = new DependentColumnFilter(Bytes.toBytes("cf-d"),
Bytes.toBytes("col-1"),
"false",
CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes("val-1"))))
scan.setFilter(filter);
一种更复杂的过滤器,不止简单的通过用户指定的信息筛选数据。允许指定一个参考列或引用列,使用参考列控制其他列的过滤。该过滤器会使用参考列的时间戳,并在过滤时包括所有与引用时间戳相同的列。
参考列过滤器相当于一个 ValueFilter 和一个时间戳过滤器的组合。
专用过滤器
单列值过滤器 SingleColumnValueFilter
使用某一列的值,决定一行数据是否被过滤。
Scan scan = new Scan();
SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("cf-d"),
Bytes.toBytes("col-5"),
CompareFilter.CompareOp.NOT_EQUAL,
new SubstringComparator("val-1"));
filter.setFilterIfMissing(true); // 如果不设置为 true,那些不包含指定列的行也会返回
scan.setFilter(filter);
对于不包含指定列的行数据,通过 setFilterIfMissing()
决定是否返回。
单列值排除器 SingleColumnValueExcludeFilter
继承自 SingleColumnValueFilter,实现的与单列值过滤器相反的语义。
行前缀过滤器 PrefixFilter
Scan scan = new Scan();
Filter filter = new PrefixFilter(Bytes.toBytes("row1"));
scan.setFilter(filter);
基于行键(Rowkey)的前缀过滤行数据。Scan 操作以字典序查找,当行键大于前缀时,Scan 结束。
列前缀过滤器 ColumnPrefixFilter
Scan scan = new Scan();
Filter filter = new ColumnPrefixFilter(Bytes.toBytes("col-"));
scan.setFilter(filter);
通过对列名称的前缀匹配过滤,返回的结果只包含满足过滤器的列。
分页过滤器 PageFilter
byte[] lastRow = null;
Filter filter = new PageFilter(10);
while(true) {
int rowCount = 0;
Scan scan = new Scan();
scan.setFilter(filter);
scan.setStartRow(lastRow);
ResultScanner resultScanner = table.getScanner(scan);
Iterator<Result> resultIterator = resultScanner.iterator();
while (resultIterator.hasNext()) {
Result result = resultIterator.next();
// ...
lastRow = result.getRow(); // 记录最后一行的rowkey
rowCount++; // 记录本页行数
}
if(rowCount <= 10) {
break;
}
}
使用该过滤器,对结果进行按行分野,需要指定 pageSize 参数,控制每页返回的行数,并设置 startRow 多次调用 getScanner(),感觉功能只适用于一些特殊场景,性能也并不高。
行键过滤器 KeyOnlyFilter
KeyOnlyFilter filter = new KeyOnlyFilter();
KeyOnlyFilter filter = new KeyOnlyFilter(true);
这个 Filter 只会返回每行的行键+列簇+列,而不返回值(value),对不需要值的应用场景来说,非常实用,减少了值的传递。构造方法可以设置 lenAsValue
参数(默认 false),表示返回时,value 设为原列值的长度。
首次行键过滤器 FirstKeyOnlyFilter
FirstKeyOnlyFilter filter = new FirstKeyOnlyFilter();
这个 Filter 仅仅返回每一行中的第一个 cell 的值,可以用于高效的执行行数统计操作,在扫描到第一个 cell 时,立即跳到下一行数据,性能相比全表扫描得到提升。
包含结束的过滤器 InclusiveStopFilter
Filter filter = new InclusiveStopFilter(Bytes.toBytes("uid-10"));
一般的扫描结果中,设置一个开始行键和一个终止行键,是前闭后开区间,不包含结束行,使用这个过滤器时将结束行加入到结果中。
时间戳过滤器 TimestampsFilter
Filter filter = new TimestampsFilter(Arrays.asList(5L, 10L, 15L));
Scan scan1 = new Scan();
scan1.setMaxVersions(3)
scan1.setFilter(filter);
Scan scan2 = new Scan();
scan2.setMaxVersions(3)
scan2.setFilter(filter);
scan2.setTimeRange(8, 12);
当需要在扫描结果中对版本进行细粒度控制时,可以使用这个 Filter 传入一个时间戳集合,对时间进行限制,只会返回与指定时间戳相同的版本数据,并且与设置时间戳范围共同使用。
列计数过滤器 ColumnCountGetFilter
Filter filter = new ColumnCountGetFilter(10);
使用这个过滤器,限制每行最多返回多少列。注意当一行的列数达到设定的最大值,过滤器会停止 Scan 操作,所以不适合全表扫描,适合在 Get 方法中使用。
列分页过滤器 ColumnPaginationFilter
Filter filter = new ColumnPaginationFilter(10,5);
与 PageFilter 类似,可以对一行的所有列进行分也,需要传入偏移量 offset 和返回数量 limit。
随机行过滤器 RandomRowFilter
Filter filter = new RandomRowFilter(0.5F);
这个 Filter 可以使结果中包含随机行,参数 chance 取值在 0.0 到 1.0 之间,表示随机取行数的比例,每一行会调用 Random.nextFloat() 与 chance 比较来确定是否被过滤。
附加过滤器
普通过滤器可以提供对返回结果的筛选限制,一些额外的控制可以附加在过滤器上
跳转过滤器 SkipFilter
Scan scan = new Scan();
Filter filter1 = new ValueFilter(CompareFilter.CompareOp.NOT_EQUAL,
new BinaryComparator(Bytes.toBytes("val-0")));
Filter filter2 = new SkipFilter(filter1);
包装了用户的一个过滤器,当过滤器发现某一行的一列需要过滤时,整行数据都被过滤掉。上面的例子是,使用 SkipFilter 和 ValueFilter 组合,获取不等于指定列值的行,同时过滤掉其他不符合条件的行(即只要有一行中一列的值等于“val-0”,就会被过滤)。
全匹配过滤 WhileMatchFilter
Scan scan = new Scan();
Filter filter1 = new ValueFilter(CompareFilter.CompareOp.NOT_EQUAL,
new BinaryComparator(Bytes.toBytes("val-0")));
Filter filter2 = new WhileMatchFilter(filter1);
与SkipFilter 相似,不过当一条数据被过滤掉时,会停止 Scan 操作。可以用来检查全表数据中,是否有某些数据不符合条件。
多种过滤条件的使用方法
通过 FilterList 实例可以提供多个过滤器共同使用的功能。并且可以指定对多个过滤器的过滤结果如何组合。
FilterList 构造函数和方法
FilterList(List<Filter> rowFilters)
FilterList(Operator operator)
FilterList(Operator operator, List<Filter> rowFilters)
void addFilter(Filter filter)
FilterList.Operator 决定了过滤器集合 List<Filter> rowFilters 的组合结果,可选值:
MUST_PASS_ALL // 当所有过滤器都允许包含这个值时,才会加入到结果中
MUST_PASS_ONE // 只需要有一个过滤器允许包含这个值时,就会加入到结果中
代码示例:
Filter filter1 = new ...;
Filter filter2 = new ...;
Filter filter3 = new ...;
FilterList filterList = new FilterList(Arrays.asList(filter1, filter2, filter3));
Scan scan = new Scan();
scan.setFilter(filterList);
References:
《HBase 权威指南》