Hbase之Client-scan请求过滤器Filter
0 前言
在Hbase的Client对Hbase的数据进行请求的时候,实际上是可以通过过滤器进行数据的筛选的,Hbase的客户端请求过滤器大致分为5种类,具体详情请参考官方。
-
FilterList 【传入过滤器列表,按照MUST_PASS_ONE \MUST_PASS_ALL的规则进行使用】
-
Column Value Filter【为列值维度的过滤,通过特定的value与具体column的值进行匹配】
-
MetaData Filter【为元数据的过滤,可以在扫描之前限定需要扫描的列族、列,避免扫描不需要的数据】
-
RowFilter 【为行过滤器,可以按照rowkey进行匹配】
-
Utility Filter 【为工具型的过滤器,一般用于进行hbase table rowcount操作】
1 FilterList(结构型过滤器)
常用的结构型的过滤器有FilterList
,该类的血缘关系如下:
java.lang.Object
org.apache.hadoop.hbase.filter.Filter
org.apache.hadoop.hbase.filter.FilterBase
org.apache.hadoop.hbase.filter.FilterList
FilterList
简单使用代码如下:
Connection connection = ConnectionFactory.createConnection();
//创建过滤器列表的实例,可以装在多个实例
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
//预先准备需要扫描的cf和column-qualifier
byte[] cf = Bytes.toBytes("");
byte[] cq = Bytes.toBytes("");
byte[] value1 = Bytes.toBytes("SuperMan");
byte[] value2 = Bytes.toBytes("BiteMan");
Filter filter1 = TestColumnValueFilter.getSingleColumnValueFilter(cf, cq, value1);
Filter filter2 = TestColumnValueFilter.getSingleColumnValueFilter(cf, cq, value1);
//添加过滤器
filterList.addFilter(filter1);
filterList.addFilter(filter2);
//获取table的实例
Table table = connection.getTable(TableName.valueOf(""));
Scan scan = new Scan();
scan.setFilter(filterList);
scan.setBatch(10000);
ResultScanner scanner = table.getScanner(scan);
//获取scanner中的数据,并进行操作
2 Column Value Filter(列值过滤器)
常用的列值过滤器有ColumnValueFilter
,SingleColumnValueFilter
,一般列值过滤器还可以配置不同的比较器配合使用;后者作为Hbase2.0.0之后对前者的完善,将row级别的匹配精确到了Cell,2者拥有相同的构造函数,简单的使用单吗如下。
package com.shufang.filter;
import org.apache.hadoop.hbase.CompareOperator;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
/**
* 常用的Column-Value相关的过滤器有:
* @FilterList: 可以用来装在多个过滤器,同时可选择对所有的Filter的配置MUST_PASS_ONE 与 MUST_PASS_ALL之间的过滤规则;
* @ColumnValueFilter: 返回匹配的Cell,是Hbase在2.0.0的时候对之前版本SingleColumnValueFilter的补充;
* @SingleColumnValueFilter: 返回匹配到的所有value的所在row的所有数据内容;
* @ValueFilter: 这个需要在scan的时候预先.addFamily().addColumn(),一般用于简单的查询类似于where$name=name;
*
* 一般的列值过滤器都是配合不同的列值比较器进行使用,常用的列值比较器如下。
* @RegexStringComparator: 正则字符串比较器
* @SubStringComparator: 子字符串比较器
* @BinaryPrefixComparator: 二进制前缀比较器
* @BinaryComparator: 二进制比较器
* @BinaryComponentComparator: 二进制组建比较器,用特定位置的特定值与Cell进行比较,可以对比ascii和binary数据
*
*/
public class TestColumnValueFilter {
public static void main(String[] args) throws IOException {
Connection connection = ConnectionFactory.createConnection();
//创建过滤器列表的实例,可以装在多个实例
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
//预先准备需要扫描的cf和column-qualifier
byte[] cf = Bytes.toBytes("");
byte[] cq = Bytes.toBytes("");
byte[] value1 = Bytes.toBytes("SuperMan");
byte[] value2 = Bytes.toBytes("BiteMan");
/**
* 对于简单的过滤条件,如:$value = cf:col:value,这种,官方强烈推荐使用ValueFilter,
* 而不是
* @ColumnValueFilter and
* @SingleColumnValueFilter
* 实例代码如下
*/
scan.addColumn(cf,cq); //限定扫描额ColumnFamily和Column,避免扫描无关的列
scan.setFilter(new ValueFilter(CompareOperator.EQUAL,new BinaryComparator(value1)));
/**
* 除了对特定value值的过滤支持,ColumnValueFilter还支持另外一种构造参数的过滤方式。
* @ColumnValueFilter(
* final byte[] family,
* final byte[] qualifier,
* final CompareOperator op,
* final ByteArrayComparable comparator
* TODO 这个参数是一种value的拓展比较方式,可以使用正则、字符串截取进行匹配
* )
* @regexStringComparator 正则匹配字符串
* @substringComparator
*/
RegexStringComparator regexStringComparator = new RegexStringComparator("my."); //所有以my开头的row
new SingleColumnValueFilter(cf,cq,CompareOperator.EQUAL,regexStringComparator);
SubstringComparator substringComparator = new SubstringComparator("y val"); //所有包含y val的row,my value会匹配出来
new SingleColumnValueFilter(cf,cq,CompareOperator.EQUAL,substringComparator);
}
/**
* @SingleColumnValueFilter :对特定value值的所有row进行等值,不等值,或者范围range的筛选
* CompareOperator.EQUAL
* CompareOperator.NOT_EQUAL
* CompareOperator.GREATER
* @param cf
* @param cq
* @param value
* @return SingleColumnValueFilter
*/
public static Filter getSingleColumnValueFilter(byte[] cf,byte[] cq,byte[] value){
return new SingleColumnValueFilter(cf,cq,CompareOperator.EQUAL,value);
}
/**
* @ColumnValueFilter :在Hbase2.0.0之后,引入了ColumnValueFilter对SingleColumnValueFilter作补充,
* 仅获取匹配到的value所在的Column的Cell,SingleColumnValueFilter会获取到匹配到的value的所在ROW的所
* 有数据,包括其它列
* TODO ColumnValueFilter的构造器参数与SingleColumnValueFilter是保持一致的
* @param cf
* @param cq
* @param value
* @return ColumnValueFilter
*/
public static Filter getColumnValueFilter(byte[] cf,byte[] cq,byte[] value){
return new ColumnValueFilter(cf,cq,CompareOperator.EQUAL,value);
}
}
3 MetaData Filter(元数据级别过滤器)
Hbase支持在扫描之从原数据层面进行过滤,避免不必要的扫描资源性能消耗,常用的此类过滤器有FamilyFilter
,QualifierFilter
,ColumnPrefixFilter
,MutipleColumnPrefixFilter
,ColumnRangeFilter
关于这些过滤器的简单使用代码如下。
package com.shufang.filter;
import com.shufang.charactor01.TestHbaseConnection;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
/**
* Hbase的过滤器除了列值过滤器之外还有MetaData相关的过滤器
*
* @FamilyFilter:列族过滤器,但是官方建议还是使用scan.addFamily()的方式比较好;
* @QualifierFilter:列过滤器,但是官方还是建议使用scan.addColumn()的方式会比较好;
* @ColumnPrefixFilter:列前缀过滤器,将指定前缀的columnQualifier的所有列进行选定匹配;
* @MutipleColumnPrefixFilter:可以同时匹配多个前缀对应的所有Column的数据,是对上者的一种补充; 具体可以参考以下实例代码
* @ColumnRangeFilter:用来从大量列中筛选出所需的列;
*/
public class TestHbaseMetaFilter {
public static void main(String[] args) throws IOException {
//使用工具创建一个Connection对象
Connection connection = TestHbaseConnection.getConnection(HBaseConfiguration.create());
//获取Table的实例
Table table = connection.getTable(TableName.valueOf("test1"));
byte[] family = Bytes.toBytes("cf");
byte[] qualifier = Bytes.toBytes("cq");
//创建scan,配置family和column
Scan scan = new Scan();
//scan.addColumn(family, qualifier);
scan.setFilter(new FamilyFilter(CompareOperator.EQUAL,new BinaryComparator(family))); //设置列族过滤器
scan.setFilter(new QualifierFilter(CompareOperator.EQUAL,new BinaryComparator(qualifier))); //设置列过滤器
/**
* @ColumnPrefixFilter
*/
ColumnPrefixFilter abc = new ColumnPrefixFilter(Bytes.toBytes("abc"));
//scan.setFilter(abc);
/**
* @MultipleColumnPrefixFilter
*/
byte[][] prefixs = {Bytes.toBytes("abc"),Bytes.toBytes("xyz")};
MultipleColumnPrefixFilter multipleColumnPrefixFilter = new MultipleColumnPrefixFilter(prefixs);
scan.setFilter(multipleColumnPrefixFilter);
/**
* @ColumnRangeFilter:假如Table有100W个列,我只需要[minColumn,macCloumn)区间的列的数据;
*/
ColumnRangeFilter columnRangeFilter = new ColumnRangeFilter(Bytes.toBytes("minColumn"),
true, Bytes.toBytes("maxColumn"), false);
scan.setFilter(columnRangeFilter);
/**
* 然后开始扫描结果,并处理获取到的结果
*/
ResultScanner rs = table.getScanner(scan);
for (Result r = rs.next(); r != null; r = rs.next()) {
for (Cell cell : r.rawCells()) {
//每个Cell就代表Column与Row的交接处的一个单元,一个Cell可能有多个Version的value,默认返回最大时间戳的
byte[] value = CellUtil.cloneValue(cell);
//现在就可以处理获取到的结果value了
}
}
rs.close(); //释放内存资源
}
}
4 RowFilter(行级别的过滤)
在早期的Hbase版本,可以使用scan.setStartRow(),scan.setStopRow() 限定范围,但是这些方法在今后的版本都被标示成过期状态,所以目前有一种过滤器的方式来进行过滤。
对于Row级别的Filter,有2种简单的API可供使用scan.setRowPrefixFilter(Bytes.toBytes("prefix_of_rowkey"))
,还可以使用scan.setFilter(new RowFilter(comparator_oper.EQUAL,new ByteArrayComparator()))
的方式进行筛选,简单使用代码如下。
package com.shufang.filter;
import com.shufang.charactor01.TestHbaseConnection;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.BinaryComparator;
import org.apache.hadoop.hbase.filter.RowFilter;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
/**
* 通常Hbase对行的过滤,可以通过startRow与stopRow进行过滤(但是在Hbase2.X后续版本中标示为过时),
* 但是通过RowFilter也是可以进行过滤操作的!
*
* @RowFilter
*/
public class TestRowFilter {
public static void main(String[] args) throws IOException {
Connection conn = TestHbaseConnection.getConnection(HBaseConfiguration.create());
Table table = conn.getTable(TableName.valueOf("test"));
/**
* 1、常规的通过scan的原生方法进行过滤
*/
Scan scan = new Scan();
//scan.setStartRow()
//scan.setStopRow()
/**
* 2、通过RowFilter进行过滤
* @RowFilter可以配合@BinaryComponentComparator等比较器进行配合使用,还能扩展过滤功能
*/
scan.setRowPrefixFilter(Bytes.toBytes("prefix1"));//按照Row的前缀进行过滤匹配
scan.setFilter(new RowFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("momoji"))));
ResultScanner scanner = table.getScanner(scan);
for (Result r = scanner.next(); r != null ; r= scanner.next()) {
Cell[] cells = r.rawCells();
for (Cell cell : cells) {
//处理cell中的数据
byte[] value = CellUtil.cloneValue(cell);
cell.getTimestamp(); //查看Cell对应的版本时间戳。
//.......
}
}
scanner.close();//释放资源
}
}
5 Utility Filter(工具型过滤器)
常用的工具型过滤器有FirstKeyOnlyFilter
,该过滤器会返回扫描结果的所有row的第一个KV,一般可以用来进行Hbase的rowcount操作,简单代码如下:
package com.shufang.filter;
import com.shufang.charactor01.TestHbaseConnection;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
import java.io.IOException;
/**
* Hbase除了列值、row、元数据过滤器之外,还有工具型的过滤器
*
* @FirstKeyOnlyFilter:只会返回每行的第一个KV,这里的KV代表一个Cell,在hbase需要进行rowcount的时候很实用
*/
public class TestUtilityFilter {
public static void main(String[] args) throws IOException {
Connection conn = TestHbaseConnection.getConnection(HBaseConfiguration.create());
Table table = conn.getTable(TableName.valueOf(""));
ResultScanner rs = null;
try {
Scan scan = new Scan();
scan.setFilter(new FirstKeyOnlyFilter());
rs = table.getScanner(scan);
//handle the rs with rs.next()
Long sum = 0l;
for (Result r = rs.next(); r != null ; r= rs.next()) {
sum+=1;
Cell[] cells = r.rawCells();
for (Cell cell : cells) {
//处理cell中的数据
byte[] value = CellUtil.cloneValue(cell);
cell.getTimestamp(); //查看Cell对应的版本时间戳。
//.......
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
rs.close();
table.close();
}
}
}