HbaseFilter

Filter

  • CompareFilter
    是高层的抽象类,下面我们将看到他的实现类和实现类代表的各种过滤条件

  • RowFilter,FamliyFilter,QualifierFilter,ValueFilter
    行,列组,列,值等的过滤

  • SingleColumnValueFilter
    单值过滤器是以特定“列”的“值”为过滤内容,值得是单列的值。而行值过滤器比较的是所有列的值。与其进行比较。

  • FilterMissing
    指的是对于找不到该列的行的时候,做的特殊处理。true,不返回该行,false 返回该行

  • PrefixFilter
    前缀过滤器将会过滤掉不匹配的记录,过滤的对象是主键的值。

  • PageFilter
    分页过滤器,通过pageSize设置每次返回的行数,这需要客户端在遍历的时候记住页开始的地方,配合scan的startkey一起使用

  • FilterList
    过滤器集合,Hbase的过滤器设计遵照于设计模式中的组合模式,以上的所有过滤器都可以叠加起来共同作用于一次查询

  • KeyOnlyFilter
    设置过滤的结果集中只包含键而忽略值

  • FirstKeyOnlyFilter
    在键过滤器的基础上,根据列有序,只包含第一个满足的键,返回每个行的第一列的KV,可以用于有效的执行行计数操作。

  • ColumnPrefixFilter
    这里过滤的对象是列的值。

  • TimestampsFilter
    这里参数是一个集合,只有包含在集合中的版本才会包含在结果集中

Demo

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

(2)比较器 ByteArrayComparable
通过比较器可以实现多样化目标匹配效果,比较器有以下子类可以使用:
BinaryComparator 按字节索引顺序比较指定字节数组,采用Bytes.compareTo(byte[])
BinaryPrefixComparator 跟前面相同,只是比较左端的数据是否相同
BitComparator 按位比较 a BitwiseOp class 做异或,与,并操作
NullComparator 判断给定的是否为空
RegexStringComparator 正则表达式匹配
SubstringComparator 断提供的子串是否出现在table的value中

1,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)

注意:根据列的值来决定这一行数据是否返回,落脚点在行,而不是列。我们可以设置filter.setFilterIfMissing(true);如果为true,当这一列不存在时,不会返回,如果为false,当这一列不存在时,会返回所有的列信息

测试数据
这里写图片描述

Table table = connection.getTable(TableName.valueOf("user"));  
        SingleColumnValueFilter scvf= new SingleColumnValueFilter(Bytes.toBytes("account"), Bytes.toBytes("name"),   
             CompareOp.EQUAL,"zhangsan".getBytes());  
        scvf.setFilterIfMissing(true); //默认为false, 没有此列的数据也会返回 ,为true则只返回name=lisi的数据  
        Scan scan = new Scan();  
        scan.setFilter(scvf);  
        ResultScanner resultScanner = table.getScanner(scan);  
        for (Result result : resultScanner) {  
             List<Cell> cells= result.listCells();      
             for (Cell cell : cells) {  
                 String row = Bytes.toString(result.getRow());  
                 String family1 = Bytes.toString(CellUtil.cloneFamily(cell));  
                 String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));  
                 String value = Bytes.toString(CellUtil.cloneValue(cell));  
                 System.out.println("[row:"+row+"],[family:"+family1+"],[qualifier:"+qualifier+"]"  
                        + ",[value:"+value+"],[time:"+cell.getTimestamp()+"]");  
            }  
        }  

一般只会设置这个
如果setFilterIfMissing(true), 有匹配只会返回当前列所在的行数据,基于行的数据 country 也返回了,因为他么你的rowkey是相同的

[row:zhangsan_1495527850824],[family:account],[qualifier:country],[value:china],[time:1495636452285]  
[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729]  

如果setFilterIfMissing(false),有匹配的列的值相同会返回,没有此列的 name的也会返回,, 不匹配的name则不会返回。
下面 红色是匹配列内容的会返回,其他的不是account:name列也会返回,, name=lisi的不会返回,因为不匹配。

[row:lisi_1495527849910],[family:account],[qualifier:idcard],[value:42963319861234561230],[time:1495556647872]  
[row:lisi_1495527850111],[family:account],[qualifier:password],[value:123451231236],[time:1495556648013]  
[row:lisi_1495527850114],[family:address],[qualifier:city],[value:黄埔],[time:1495556648017]  
[row:lisi_1495527850136],[family:address],[qualifier:province],[value:shanghai],[time:1495556648041]  
[row:lisi_1495527850144],[family:info],[qualifier:age],[value:21],[time:1495556648045]  
[row:lisi_1495527850154],[family:info],[qualifier:sex],[value:女],[time:1495556648056]  
[row:lisi_1495527850159],[family:userid],[qualifier:id],[value:002],[time:1495556648060]  
[row:wangwu_1495595824517],[family:userid],[qualifier:id],[value:009],[time:1495624624131]  
[row:zhangsan_1495527850759],[family:account],[qualifier:idcard],[value:9897645464646],[time:1495556648664]  
[row:zhangsan_1495527850759],[family:account],[qualifier:passport],[value:5689879898],[time:1495636370056]  
[row:zhangsan_1495527850824],[family:account],[qualifier:country],[value:china],[time:1495636452285]  
<span style="color:#ff0000;">[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729]</span>  
[row:zhangsan_1495527850951],[family:address],[qualifier:province],[value:guangdong],[time:1495556648855]  
[row:zhangsan_1495527850975],[family:info],[qualifier:age],[value:100],[time:1495556648878]  
[row:zhangsan_1495527851080],[family:info],[qualifier:sex],[value:男],[time:1495556648983]  
[row:zhangsan_1495527851095],[family:userid],[qualifier:id],[value:001],[time:1495556648996]  

3 键值元数据
由于HBase 采用键值对保存内部数据,键值元数据过滤器评估一行的键(ColumnFamily:Qualifiers)是否存在

3.1. 基于列族过滤数据的FamilyFilter
构造函数:
FamilyFilter(CompareFilter.CompareOp familyCompareOp, ByteArrayComparable familyComparator)
代码如下:

public static ResultScanner getDataFamilyFilter(String tableName,String family) throws IOException{  
        Table table = connection.getTable(TableName.valueOf("user"));  
        FamilyFilter ff = new FamilyFilter(CompareOp.EQUAL ,   
                new BinaryComparator(Bytes.toBytes("account")));   //表中不存在account列族,过滤结果为空  
//       new BinaryPrefixComparator(value) //匹配字节数组前缀  
//       new RegexStringComparator(expr) // 正则表达式匹配  
//       new SubstringComparator(substr)// 子字符串匹配   
        Scan scan = new Scan();  
        // 通过scan.addFamily(family)  也可以实现此操作  
        scan.setFilter(ff);  
        ResultScanner resultScanner = table.getScanner(scan);  
        return resultScanner;  
    }  

测试结果:查询的都是account列簇的内容

[row:lisi_1495527849910],[family:account],[qualifier:idcard],[value:42963319861234561230],[time:1495556647872]  
[row:lisi_1495527850081],[family:account],[qualifier:name],[value:lisi],[time:1495556647984]  
[row:lisi_1495527850111],[family:account],[qualifier:password],[value:123451231236],[time:1495556648013]  
[row:zhangsan_1495527850759],[family:account],[qualifier:idcard],[value:9897645464646],[time:1495556648664]  
[row:zhangsan_1495527850759],[family:account],[qualifier:passport],[value:5689879898],[time:1495636370056]  
[row:zhangsan_1495527850824],[family:account],[qualifier:country],[value:china],[time:1495636452285]  
[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729]  

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

    Table table = connection.getTable(TableName.valueOf("user"));  
        QualifierFilter ff = new QualifierFilter(  
                CompareOp.EQUAL , new BinaryComparator(Bytes.toBytes("name")));  
//       new BinaryPrefixComparator(value) //匹配字节数组前缀  
//       new RegexStringComparator(expr) // 正则表达式匹配  
//       new SubstringComparator(substr)// 子字符串匹配   
        Scan scan = new Scan();  
        // 通过scan.addFamily(family)  也可以实现此操作  
        scan.setFilter(ff);  
        ResultScanner resultScanner = table.getScanner(scan);  

测试结果:只返回 name 的列内容

[row:lisi_1495527850081],[family:account],[qualifier:name],[value:lisi],[time:1495556647984]  
[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729]  

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

Table table = connection.getTable(TableName.valueOf("user"));  
         ColumnPrefixFilter ff = new ColumnPrefixFilter(Bytes.toBytes("name"));  
        Scan scan = new Scan();  
        // 通过QualifierFilter的 newBinaryPrefixComparator也可以实现  
        scan.setFilter(ff);  
        ResultScanner resultScanner = table.getScanner(scan);  

返回结果:

[row:lisi_1495527850081],[family:account],[qualifier:name],[value:lisi],[time:1495556647984]  
[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729] 

3.4. 基于多个列名(即Qualifier)前缀过滤数据的MultipleColumnPrefixFilter
MultipleColumnPrefixFilter 和 ColumnPrefixFilter 行为差不多,但可以指定多个前缀

byte[][] prefixes = new byte[][] {Bytes.toBytes("name"), Bytes.toBytes("age")};  
        //返回所有行中以name或者age打头的列的数据  
        MultipleColumnPrefixFilter ff = new MultipleColumnPrefixFilter(prefixes);  

        Scan scan = new Scan();  
        scan.setFilter(ff);  
        ResultScanner rs = table.getScanner(scan);    

结果:

[row:lisi_1495527850081],[family:account],[qualifier:name],[value:lisi],[time:1495556647984]  
[row:lisi_1495527850144],[family:info],[qualifier:age],[value:21],[time:1495556648045]  
[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729]  
[row:zhangsan_1495527850975],[family:info],[qualifier:age],[value:100],[time:1495556648878] 

4.RowKey
当需要根据行键特征查找一个范围的行数据时,使用Scan的startRow和stopRow会更高效,但是,startRow和stopRow只能匹配行键的开始字符,而不能匹配中间包含的字符:
byte[] startColumn = Bytes.toBytes(“azha”);
byte[] endColumn = Bytes.toBytes(“dddf”);
Scan scan = new Scan(startColumn,endColumn);

当需要针对行键进行更复杂的过滤时,可以使用RowFilter:

构造函数:
RowFilter(CompareFilter.CompareOp rowCompareOp, ByteArrayComparable rowComparator)

Table table = connection.getTable(TableName.valueOf("user"));  
        RowFilter rf = new RowFilter(CompareOp.EQUAL ,   
                new SubstringComparator("zhangsan"));  
        //       new BinaryPrefixComparator(value) //匹配字节数组前缀  
        //       new RegexStringComparator(expr) // 正则表达式匹配  
        //       new SubstringComparator(substr)// 子字符串匹配   
        Scan scan = new Scan();  
        scan.setFilter(rf);  
        ResultScanner rs = table.getScanner(scan);   

结果:

[row:zhangsan_1495527850759],[family:account],[qualifier:idcard],[value:9897645464646],[time:1495556648664]  
[row:zhangsan_1495527850759],[family:account],[qualifier:passport],[value:5689879898],[time:1495636370056]  
[row:zhangsan_1495527850824],[family:account],[qualifier:country],[value:china],[time:1495636452285]  
[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729]  
[row:zhangsan_1495527850951],[family:address],[qualifier:province],[value:guangdong],[time:1495556648855]  
[row:zhangsan_1495527850975],[family:info],[qualifier:age],[value:100],[time:1495556648878]  
[row:zhangsan_1495527851080],[family:info],[qualifier:sex],[value:男],[time:1495556648983]  
[row:zhangsan_1495527851095],[family:userid],[qualifier:id],[value:001],[time:1495556648996]  

5.PageFilter
疑问:怎么做分页?
指定页面行数,返回对应行数的结果集。
需要注意的是,该过滤器并不能保证返回的结果行数小于等于指定的页面行数,因为过滤器是分别作用到各个region server的,它只能保证当前region返回的结果行数不超过指定页面行数。
构造函数:
PageFilter(long pageSize)
代码:

Table table = connection.getTable(TableName.valueOf("user"));  
        PageFilter pf = new PageFilter(2L);  
        Scan scan = new Scan();  
        scan.setFilter(pf);  
        scan.setStartRow(Bytes.toBytes("zhangsan_"));  
        ResultScanner rs = table.getScanner(scan);  

结果:返回的结果实际上有四条,因为这数据来自不同RegionServer,

[row:zhangsan_1495527850759],[family:account],[qualifier:idcard],[value:9897645464646],[time:1495556648664]  
[row:zhangsan_1495527850759],[family:account],[qualifier:passport],[value:5689879898],[time:1495636370056]  
[row:zhangsan_1495527850824],[family:account],[qualifier:country],[value:china],[time:1495636452285]  
[row:zhangsan_1495527850824],[family:account],[qualifier:name],[value:zhangsan],[time:1495556648729]  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值