[TOC]
任务描述
本关任务:
相关知识
有时候我们可能也想要有自己的,这个时候可以使用自定义过滤器。
自定义过滤器
定义一个自定义过滤器其实很简单——继承Filter
类(之前Filter
是一个接口)或者直接继承FilterBase
类即可,后者已经为Filter
类中的抽象方法提供了默认的实现。
Filter
类的结构如下,因为代码较多,只展示核心部分:
public abstract class Filter {
public enum ReturnCode { INCLUDE,INCLUDE_AND_NEXT_COL,SKIP,NEXT_COL,NEXT_ROW,SEEK_NEXT_USING_HINT,INCLUDE_AND_SEEK_NEXT_ROW,
}
abstract public void reset() throws IOException;
abstract public boolean filterRowKey(Cell firstRowCell) throws IOException;
abstract public boolean filterAllRemaining() throws IOException;
public ReturnCode filterCell(final Cell c) throws IOException{
return filterKeyValue(c);
}
abstract public Cell transformCell(final Cell v) throws IOException;
abstract public void filterRowCells(List kvs) throws IOException;
abstract public boolean hasFilterRow();
abstract public boolean filterRow() throws IOException;
abstract public Cell getNextCellHint(final Cell currentCell) throws IOException;
abstract public boolean filterAllRemaining() throws IOException;
}
|
HBase所有的过滤器都是通过继承Filter
或者FilterBase
来实现的,要想自定义过滤器,我们需要先理解过滤器父类方法的含义,这样才能更好的使用自定义过滤器。
如何使用自定义过滤器
首先我们来了解Filter
类中方法的含义:
-
FilterRowKey(byte[] buffer,int offset,int length)
本方法使用Filter
的实现方法检查行键,用户可以跳过整行数据以避免之后的处理,RowFilter
使用这个方法来筛选符合条件的行并返回给客户端。 -
filterCell(Cell c)
如果本行的数据没有被之前的方法过滤掉,那么执行框架会调用这个方法检查这一行中。 -
filterRowCells(List
一旦所有行和列经过之前两个方法的检查之后,这个方法就会被调用。本方法让用户可以访问之前两个方法筛选出来的kvs) | Cell
实例。 -
filterRow(List
以上的所有方法都调用完成之后,本方法就会执行,kvs) PageFilter
就是使用当前方法来检查在一次迭代分页中返回的行数是否达到预期的页大小,如果达到页大小则返回true
。默认返回值为false
,此时结果中包含当前行。 -
reset()
在迭代扫描中为每个新行重置过滤器。服务器端读取一行数据后,这个方法会被隐式地调用。 -
filterAllRemaining()
当这个方法返回true
时,可以用于结束整个扫描操作,用户使用这个方法被过滤器用于提供上述的优化——提前结束。在一个过滤中,如果这个方法返回false
。扫描操作会继续执行,同时前面介绍的方法会再次被调用。
Filter
类中有一个公有的枚举类型,叫做ReturnCode
,它被filterCell()
方法用于通知执行框架,进而决定如何进行下一步的工作。过滤器可以跳过一个值、一列的剩余部分或一行的剩余部分,而不用遍历所有数据。因此获取数据的效率会大大提升。
通过filterCell()
可以返回一个类型的值,
的值类型
返回值 | 描述 |
---|---|
INCLUDE | 在结果中包括这个Cell的实例 |
SKIP | 跳过这个Cell实例并继续处理接下来的工作 |
NEXT_COL | 跳过当前列并继续处理后面的列。例如,TimeStampsFilter使用了这个返回值 |
NEXT_ROW | 与上面的行为类似,跳过当前行并继续处理下一行。例如,RowFilter使用了这个返回值 |
SEEK_NEXT_USING_HINT | 一些过滤器需要跳过一系列的值,此时需要使用这个返回值通知执行框架使用getNextKeyHint()来决定跳到什么位置。例如,ColumnPrefixFilter使用了这个功能 |
实现自定义过滤器
纸上得来终觉浅,咱们学习过滤器需要用来解决实际问题;
现在要从下表中查询出包含value2.1
值的行,并输出整行数据。
[图片上传失败...(image-17dfff-1545742384688)]
首先,我们通过继承FilterBase
来定义一个自定义过滤器:
class MyFilter extends FilterBase{
private byte[] value = null;
private boolean filterRow = true;
public MyFilter() {
super();
}
public MyFilter(byte[] value) {
//(1)设置要比较的值
this.value = value;
}
public void reset() throws IOException {
//(2)每当有新行时重置FilterRow的值为true,即重置标志位
this.filterRow = true;
}
public ReturnCode filterKeyValue(Cell c) throws IOException {
byte[] cellValue = CellUtil.cloneValue(c);
if(Bytes.compareTo(value, cellValue) == 0){
//(3)当值匹配时,让这一行通过过滤
filterRow = false;
}
//(4)总是先包含Cell实例,直到filterRow()决定是否过滤这一行。
return ReturnCode.INCLUDE;
}
public boolean filterRow(){
//(5)这是决定数据是否被返回的一行,基于标志位判断
return filterRow;
}
public void write(DataOutput dataOutput)throws IOException{
//(6)把值写到DataOutput中,服务端实例化过滤器时可以读到这个值
Bytes.writeByteArray(dataOutput, this.value);
}
public void readFields(DataInput dataInput)throws IOException{
//(7)服务端使用这个方法来初始化过滤器对象,所以客户端的设定值可以被读取到
this.value = Bytes.readByteArray(dataInput);
}
}
通过上述步骤我们就定义了一个查找特定值的过滤器。
接下来使用这个自定义过滤器,看是否能实现查找特定值的功能。
使用自定义过滤器
使用就很简单了:
Filter myFilter = new MyFilter(Bytes.toBytes("val2.1"));
Scan scan = new Scan();
scan.setFilter(myFilter);
ResultScanner sc = table.getScanner(scan);
for (Result result : sc) {
System.out.println(Bytes.toString(result.getRow()));
for(Cell cell : result.listCells()){
String family = Bytes.toString(CellUtil.cloneFamily(cell));
String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
String value = Bytes.toString(CellUtil.cloneValue(cell));
System.out.println("\t" + family + ":" + qualifier + " " + value);
}
}
sc.close();
输出:
row3
data:1 value2.1
data:2 value2.2
data:3 value2.3
data:4 value2.4
与咱们预期的输出是一样的,一行中有一列值与预定值匹配时,这一行的数据就会被包含在结果集中。
到这,你已经学会了自定义过滤器的初步使用,我们还可以通过自定义比较器,与自定义过滤器结合的方式实现更加定制化的过滤器。
将自定义过滤器发布到HBase中
编写好的自定义过滤器还不能直接使用,需要先将它打成Jar包并发布到HBase,并保证可以被region服务器调用。
我们需要两个步骤将自定义的过滤器发布到HBase:
- 将Java文件打成Jar包;
- 将jar包路径配置到
hbase-env.sh
文件。
配置完这些属性需要重启HBase的守护进程,才能使配置生效。
编程要求
测试说明
开始你的任务吧,祝你成功!