IT技术互动交流平台

HBase(0.96以上版本)过滤器Filter详解及实例代码

来源:IT165收集  发布日期:2014-07-10 20:20:40
说明: 本文参考官方Ref Guide,Developer API和众多博客,并结合实测代码编写,详细总结HBase的Filter功能,并附上每类Filter的相应代码实现。 本文尽量遵从Ref Guide中“9.4. Client Request Filters”的行文顺序,便于读者对比查看,但内容比官方文档更加详实。 欢迎转载,请注明来源: http://blog.csdn.net/u010967382/article/details/37653177


目录: 引言 -- 参数基础 1. 结构(Structural)过滤器--FilterList 2.列值过滤器--SingleColumnValueFilter 2.1.第一种构造函数情况 -- 比较的关键字是字符数组 2.2.第二种构造函数情况 -- 比较的关键字是比较器ByteArrayComparable 3.键值元数据 3.1. 基于列族过滤数据的FamilyFilter 3.2. 基于限定符Qualifier(列)过滤数据的QualifierFilter 3.3. 基于列名(即Qualifier)前缀过滤数据的ColumnPrefixFilter 3.4. 基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter 3.5. 基于列范围(不是行范围)过滤数据ColumnRangeFilter 4. RowKey 5. Utility--FirstKeyOnlyFilter 6. 取得查询结果

引言 -- 参数基础
有两个参数类在各类Filter中经常出现,统一介绍下: (1)比较运算符 CompareFilter.CompareOp 比较运算符用于定义比较关系,可以有以下几类值供选择: EQUAL 相等
GREATER 大于
GREATER_OR_EQUAL 大于等于
LESS 小于
LESS_OR_EQUAL 小于等于
NOT_EQUAL 不等于

(2)比较器 ByteArrayComparable 通过比较器可以实现多样化目标匹配效果,比较器有以下子类可以使用: BinaryComparator 匹配完整字节数组
BinaryPrefixComparator 匹配字节数组前缀
BitComparator
NullComparator
RegexStringComparator 正则表达式匹配
SubstringComparator 子串匹配


1. 结构(Structural)过滤器--FilterList FilterList 代表一个过滤器链,它可以包含一组即将应用于目标数据集的过滤器,过滤器间具有“与” FilterList.Operator.MUST_PASS_ALL 和“或” FilterList.Operator.MUST_PASS_ONE 关系。
官网实例代码,两个“或”关系的过滤器的写法: FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE); //数据只要满足一组过滤器中的一个就可以 SingleColumnValueFilter filter1 = new SingleColumnValueFilter( cf, column, CompareOp.EQUAL, Bytes.toBytes("my value") ); list.add(filter1); SingleColumnValueFilter filter2 = new SingleColumnValueFilter( cf, column, CompareOp.EQUAL, Bytes.toBytes("my other value") ); list.add(filter2); Scan scan = new Scan(); scan.setFilter(list);
2. 列值过滤器--SingleColumnValueFilter SingleColumnValueFilter 用于测试列值相等 (CompareOp.EQUAL ), 不等 (CompareOp.NOT_EQUAL),或单侧范围 (e.g., CompareOp.GREATER)构造函数: (1)比较的关键字是一个字符数组 SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, byte[] value)
(2)比较的关键字是一个比较器(比较器下一小节做介绍) SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, ByteArrayComparable comparator)

2.1.第一种构造函数情况 -- 比较的关键字是字符数组 官网示例代码,检查列值和字符串'my value' 相等: SingleColumnValueFilter filter = new SingleColumnValueFilter( cf, column, CompareOp.EQUAL, Bytes.toBytes("my value") ); scan.setFilter(filter);
个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
SingleColumnValueFilter filter = new SingleColumnValueFilter( Bytes.toBytes("patentinfo"), Bytes.toBytes("CREATE_TIME"), CompareOp.EQUAL, Bytes.toBytes("2013-06-08") ); filterList.addFilter(filter); Scan scan = new Scan(); scan.setFilter(filterList); ResultScanner rs = table.getScanner(scan); for (Result r : rs) { System.out.println("Scan: " + r); } table.close();
注意:还是大写问题,HBase的列名必须大写!

2.2.第二种构造函数情况 -- 比较的关键字是比较器ByteArrayComparable 该章节主要是针对SingleColumnValueFilter的第二种构造函数使用情况做了一些举例: (1)支持值比较的正则表达式 -- RegexStringComparator 官网示例代码: RegexStringComparator comp = new RegexStringComparator("my."); //任意以my打头的值 SingleColumnValueFilter filter = new SingleColumnValueFilter( cf, column, CompareOp.EQUAL, comp ); scan.setFilter(filter);
个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL); RegexStringComparator comp = new RegexStringComparator("2013-06-1."); SingleColumnValueFilter filter = new SingleColumnValueFilter( Bytes.toBytes("patentinfo"), Bytes.toBytes("CREATE_TIME"), CompareOp.EQUAL, comp ); filterList.addFilter(filter); Scan scan = new Scan(); scan.setFilter(filterList); ResultScanner rs = table.getScanner(scan); for (Result r : rs) { System.out.println("Scan: " + r); } table.close();

(2)检测一个子串是否存在于值中(大小写不敏感) -- SubstringComparator 官网示例代码: SubstringComparator comp = new SubstringComparator("y val"); // looking for 'my value' SingleColumnValueFilter filter = new SingleColumnValueFilter( cf, column, CompareOp.EQUAL, comp ); scan.setFilter(filter);
个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL); // RegexStringComparator comp = new RegexStringComparator("2013-06-1."); SubstringComparator comp = new SubstringComparator("2013-06-1"); SingleColumnValueFilter filter = new SingleColumnValueFilter( Bytes.toBytes("patentinfo"), Bytes.toBytes("CREATE_TIME"), CompareOp.EQUAL, comp ); filterList.addFilter(filter); Scan scan = new Scan(); scan.setFilter(filterList); ResultScanner rs = table.getScanner(scan); for (Result r : rs) { System.out.println("Scan: " + r); } table.close();

(3)BinaryComparator 二进制比较器,用得较少,有需要请自行查阅官网:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryComparator.html
(4)BinaryPrefixComparator 二进制前缀比较器,用得较少,有需要请自行查阅官网:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/BinaryPrefixComparator.html
3. 键值元数据 由于HBase 采用键值对保存内部数据,键值元数据过滤器评估一行的键(ColumnFamily:Qualifiers)是否存在 , 对应前节所述值的情况。
3.1. 基于列族过滤数据的FamilyFilter 构造函数:
FamilyFilter(CompareFilter.CompareOp familyCompareOp, ByteArrayComparable familyComparator)

个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); /** * FamilyFilter构造函数中第二个参数是ByteArrayComparable类型 * ByteArrayComparable类参见“引言-参数基础”章节 * 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例: */ FamilyFilter ff = new FamilyFilter( CompareFilter.CompareOp.EQUAL , new BinaryComparator(Bytes.toBytes("pat")) //表中不存在pat列族,过滤结果为空 ); FamilyFilter ff1 = new FamilyFilter( CompareFilter.CompareOp.EQUAL , new BinaryPrefixComparator(Bytes.toBytes("pat")) //表中存在以pat打头的列族patentinfo,过滤结果为该列族所有行 ); Scan scan = new Scan(); scan.setFilter(ff1); ResultScanner rs = table.getScanner(scan);

注意: 如果希望查找的是一个已知的列族,则使用 scan.addFamily(family) 比使用过滤器效率更高;
由于目前HBase对多列族支持不完善,所以该过滤器目前用途不大。

3.2. 基于限定符Qualifier(列)过滤数据的QualifierFilter
构造函数: QualifierFilter(CompareFilter.CompareOp op, ByteArrayComparable qualifierComparator)

个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); /** * QualifierFilter构造函数中第二个参数是ByteArrayComparable类型 * ByteArrayComparable类有以下子类可以使用: * ******************************************* * BinaryComparator 匹配完整字节数组, * BinaryPrefixComparator 匹配开始的部分字节数组, * BitComparator, * NullComparator, * RegexStringComparator, 正则表达式匹配 * SubstringComparator * ******************************************* * 下面仅以最可能用到的BinaryComparator、BinaryPrefixComparator举例: */ QualifierFilter ff = new QualifierFilter( CompareFilter.CompareOp.EQUAL , new BinaryComparator(Bytes.toBytes("belong")) //表中不存在belong列,过滤结果为空 ); QualifierFilter ff1 = new QualifierFilter( CompareFilter.CompareOp.EQUAL , new BinaryPrefixComparator(Bytes.toBytes("BELONG")) //表中存在以BELONG打头的列BELONG_SITE,过滤结果为所有行的该列数据 ); Scan scan = new Scan(); scan.setFilter(ff1); ResultScanner rs = table.getScanner(scan);
说明: 一旦涉及到列(Qualifier),HBase就只认大写字母了!
该过滤器应该比FamilyFilter更常用!

3.3. 基于列名(即Qualifier)前缀过滤数据的ColumnPrefixFilter ( 该功能用QualifierFilter也能实现 ) 构造函数: ColumnPrefixFilter(byte[] prefix)

注意: 一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列。
官网示例代码,查找所有"abc"打头的列: HTableInterface t = ...; byte[] row = ...; byte[] family = ...; byte[] prefix = Bytes.toBytes("abc"); Scan scan = new Scan(row, row); // (optional) limit to one row scan.addFamily(family); // (optional) limit to one family Filter f = new ColumnPrefixFilter(prefix); scan.setFilter(f); scan.setBatch(10); // set this if there could be many columns returned ResultScanner rs = t.getScanner(scan); for (Result r = rs.next(); r != null; r = rs.next()) { for (KeyValue kv : r.raw()) { // each kv represents a column } } rs.close();
个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); //返回所有行中以BELONG打头的列的数据
ColumnPrefixFilter ff1 = new ColumnPrefixFilter(Bytes.toBytes("BELONG")); Scan scan = new Scan(); scan.setFilter(ff1); ResultScanner rs = table.getScanner(scan);


3.4. 基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter 说明: MultipleColumnPrefixFilter 和 ColumnPrefixFilter 行为差不多,但可以指定多个前缀。
官方示例代码,查找所有"abc"或"xyz"打头的列: HTableInterface t = ...; byte[] row = ...; byte[] family = ...; byte[][] prefixes = new byte[][] {Bytes.toBytes("abc"), Bytes.toBytes("xyz")}; Scan scan = new Scan(row, row); // (optional) limit to one row scan.addFamily(family); // (optional) limit to one family Filter f = new MultipleColumnPrefixFilter(prefixes); scan.setFilter(f); scan.setBatch(10); // set this if there could be many columns returned ResultScanner rs = t.getScanner(scan); for (Result r = rs.next(); r != null; r = rs.next()) { for (KeyValue kv : r.raw()) { // each kv represents a column } } rs.close();
个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); byte[][] prefixes = new byte[][] {Bytes.toBytes("BELONG"), Bytes.toBytes("CREATE")}; //返回所有行中以BELONG或者CREATE打头的列的数据 MultipleColumnPrefixFilter ff = new MultipleColumnPrefixFilter(prefixes);
Scan scan = new Scan(); scan.setFilter(ff); ResultScanner rs = table.getScanner(scan);


3.5. 基于列范围(不是行范围)过滤数据ColumnRangeFilter 说明: 可用于获得一个范围的列,例如,如果你的一行中有百万个列,但是你只希望查看列名为bbbb到dddd的范围该方法从 HBase 0.92 版本开始引入
一个列名是可以出现在多个列族中的,该过滤器将返回所有列族中匹配的列

构造函数: ColumnRangeFilter(byte[] minColumn, boolean minColumnInclusive, byte[] maxColumn, boolean maxColumnInclusive) 参数解释: minColumn - 列范围的最小值,如果为空,则没有下限;
minColumnInclusive - 列范围是否包含minColumn ;
maxColumn - 列范围最大值,如果为空,则没有上限;
maxColumnInclusive - 列范围是否包含maxColumn 。

官网示例代码,查找列名在"bbbb"到"dddd"范围的数据: HTableInterface t = ...;
byte[] row = ...; byte[] family = ...; byte[] startColumn = Bytes.toBytes("bbbb"); byte[] endColumn = Bytes.toBytes("bbdd"); Scan scan = new Scan(row, row); // (optional) limit to one row scan.addFamily(family); // (optional) limit to one family Filter f = new ColumnRangeFilter(startColumn, true, endColumn, true); scan.setFilter(f); scan.setBatch(10); // set this if there could be many columns returned ResultScanner rs = t.getScanner(scan); for (Result r = rs.next(); r != null; r = rs.next()) { for (KeyValue kv : r.raw()) { // each kv represents a column } } rs.close();
个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); byte[] startColumn = Bytes.toBytes("C"); byte[] endColumn = Bytes.toBytes("D"); //返回所有列中从C到D打头的范围的数据,实际返回类似CREATOR、CREATE_TIME、CHANNEL_CODE等列的数据 ColumnRangeFilter ff = new ColumnRangeFilter(startColumn, true, endColumn, true); Scan scan = new Scan(); scan.setFilter(ff); ResultScanner rs = table.getScanner(scan);

4. RowKey 当需要根据行键特征查找一个范围的行数据时,使用Scan的startRow和stopRow会更高效,但是,startRow和stopRow只能匹配行键的开始字符,而不能匹配中间包含的字符: byte[] startColumn = Bytes.toBytes("aaa"); byte[] endColumn = Bytes.toBytes("bbb"); Scan scan = new Scan(startColumn,endColumn);
当需要针对行键进行更复杂的过滤时,可以使用RowFilter:
构造函数: RowFilter(CompareFilter.CompareOp rowCompareOp, ByteArrayComparable rowComparator)
参数解释参见“引言-参数基础”章节。
个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); /** * rowkey格式为:创建日期_发布日期_ID_TITLE * 目标:查找 发布日期 为 2013-07-16 的数据 */ RowFilter rf = new RowFilter( CompareFilter.CompareOp.EQUAL , new SubstringComparator("_2013-07-16_") ); Scan scan = new Scan(); scan.setFilter(rf); ResultScanner rs = table.getScanner(scan);
注意: 测试过程中尝试通过组合使用两个RowFilter(CompareFilter.CompareOp参数分别为GREATER_OR_EQUALLESS_OR_EQUAL),和SubstringComparator,过滤找出指定发布时间范围内的数据,但结果比较意外,不是预想的数据,估计比较运算符GREATER_OR_EQUALLESS_OR_EQUAL和比较器SubstringComparator组合使用效果不太好,慎用。

5. Utility--FirstKeyOnlyFilter 该过滤器仅仅返回每一行中的第一个cell的值,可以用于高效的执行行数统计操作。 估计实战意义不大。
构造函数: public FirstKeyOnlyFilter()

个人实测代码: HTable table = HBaseDAO.getHTable("147patents"); FirstKeyOnlyFilter fkof = new FirstKeyOnlyFilter(); Scan scan = new Scan(); scan.setFilter(fkof); ResultScanner rs = table.getScanner(scan);


6. 取得查询结果
无论是官网的Ref Guide还是网上流传的大部分博客中,输出查询结果的代码都是: for (Result r = rs.next(); r != null; r = rs.next()) { for (KeyValue kv : r.raw()) { // each kv represents a column } }
但查看最新的API可知Result实例的raw()方法已经不建议使用了: raw() Deprecated. as of 0.96, use rawCells()
0.96以后版本正确的获取结果代码如下: for (Result r : rs) { for (Cell cell : r.rawCells()) { System.out.println( "Rowkey : "+Bytes.toString(r.getRow())+ "Familiy:Quilifier : "+Bytes.toString(CellUtil.cloneQualifier(cell))+ "Value : "+Bytes.toString(CellUtil.cloneValue(cell)) ); } }

Tag标签: 过滤器   实例   版本  
  • 专题推荐

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规