zoukankan      html  css  js  c++  java
  • 【甘道夫】HBase(0.96以上版本号)过滤器Filter具体解释及实例代码

    说明:
    本文參考官方Ref Guide,Developer API和众多博客。并结合实測代码编写。具体总结HBase的Filter功能,并附上每类Filter的对应代码实现。
    本文尽量遵从Ref Guide中“9.4. Client Request Filters”的行文顺序,便于读者对照查看,但内容比官方文档更加详实。

    ***2014年7月18日更新。新增PageFilter和SkipFilter。

    ***


    欢迎转载,请注明来源:
    http://blog.csdn.net/u010967382/article/details/37653177


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


    引言 -- 參数基础
    有两个參数类在各类Filter中常常出现。统一介绍下:
    (1)比較运算符 CompareFilter.CompareOp
    比較运算符用于定义比較关系。能够有下面几类值供选择:
    1. EQUAL                                  相等
    2. GREATER                              大于
    3. GREATER_OR_EQUAL           大于等于
    4. LESS                                      小于
    5. LESS_OR_EQUAL                  小于等于
    6. NOT_EQUAL                        不等于

    (2)比較器  ByteArrayComparable
    通过比較器能够实现多样化目标匹配效果,比較器有下面子类能够使用:
    1. BinaryComparator               匹配完整字节数组 
    2. BinaryPrefixComparator     匹配字节数组前缀 
    3. BitComparator
    4. NullComparator
    5. RegexStringComparator    正則表達式匹配
    6. 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)比較的keyword是一个字符数组
    SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, byte[] value)
    (2)比較的keyword是一个比較器(比較器下一小节做介绍)
    SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, ByteArrayComparable comparator)

    2.1.第一种构造函数情况 -- 比較的keyword是字符数组
    官网演示样例代码检查列值和字符串'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.另外一种构造函数情况 -- 比較的keyword是比較器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); 

    注意:
    1. 假设希望查找的是一个已知的列族,则使用 scan.addFamily(family)  比使用过滤器效率更高。
    2. 因为眼下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);  
    说明:
    1. 一旦涉及到列(Qualifier),HBase就仅仅认大写字母了!
    2. 该过滤器应该比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
    说明:
    1. 可用于获得一个范围的列,比如。假设你的一行中有百万个列。可是你仅仅希望查看列名为bbbb到dddd的范围
    2. 该方法从 HBase 0.92 版本号開始引入
    3. 一个列名是能够出如今多个列族中的。该过滤器将返回全部列族中匹配的列

    构造函数:
    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.PageFilter
    指定页面行数,返回相应行数的结果集。

    须要注意的是。该过滤器并不能保证返回的结果行数小于等于指定的页面行数。由于过滤器是分别作用到各个region server的。它仅仅能保证当前region返回的结果行数不超过指定页面行数。

    构造函数:
    PageFilter(long pageSize)

    实測代码(从“2013-07-26”行開始,取5行):
                Scan scan = new Scan();
                scan.setStartRow(Bytes.toBytes("2013-07-26"));
                PageFilter pf = new PageFilter(5L);
                scan.setFilter(pf);
                ResultScanner rs = table.getScanner(scan);
                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))
                                + "   Time : " + cell.getTimestamp());
                    }
                }  
    注意:
    因为该过滤器并不能保证返回的结果行数小于等于指定的页面行数。所以更好的返回指定行数的办法是ResultScanner.next(int nbRows) ,即:
                ResultScanner rs = table.getScanner(scan);
                for (Result r : rs.next(5)) {
                    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))
                                + "   Time : " + cell.getTimestamp());
                    }
                }  


    6.SkipFilter
    依据整行中的每一个列来做过滤,仅仅要存在一列不满足条件,整行都被过滤掉。

    比如,假设一行中的全部列代表的是不同物品的重量,则真实场景下这些数值都必须大于零,我们希望将那些包括随意列值为0的行都过滤掉。
    在这个情况下。我们结合ValueFilter和SkipFilter共同实现该目的:
    scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,new BinaryComparator(Bytes.toBytes(0))));

    构造函数:
    SkipFilter(Filter filter) 

    个人实測代码:
    眼下的数据:
    hbase(main):009:0> scan 'rd_ns:itable'
    ROW                         COLUMN+CELL
     100001                     column=info:address, timestamp=1405417403438, value=anywhere
     100001                     column=info:age, timestamp=1405417403438, value=24
     100001                     column=info:name, timestamp=1405417403438, value=zhangtao
     100002                     column=info:address, timestamp=1405417426693, value=shangdi
     100002                     column=info:age, timestamp=1405417426693, value=28
     100002                     column=info:name, timestamp=1405417426693, value=shichao
     100003                     column=info:address, timestamp=1405494141522, value=huilongguan
     100003                     column=info:age, timestamp=1405494999631, value=29
     100003                     column=info:name, timestamp=1405494141522, value=liyang
    3 row(s) in 0.0190 seconds

    运行下面代码:
            Configuration conf = HBaseConfiguration.create();
            HTable table = new HTable(conf, "rd_ns:itable");
            Scan scan = new Scan();
            scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,
                    new BinaryComparator(Bytes.toBytes("28")))));
            ResultScanner rs = table.getScanner(scan);
            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))
                            + "   Time : " + cell.getTimestamp());
                }
            }
            table.close();  
    输出结果(整个100002行被过滤掉了):
    Rowkey : 100001   Familiy:Quilifier : address   Value : anywhere   Time : 1405417403438
    Rowkey : 100001   Familiy:Quilifier : age   Value : 24   Time : 1405417403438
    Rowkey : 100001   Familiy:Quilifier : name   Value : zhangtao   Time : 1405417403438
    Rowkey : 100003   Familiy:Quilifier : address   Value : huilongguan   Time : 1405494141522
    Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405494999631
    Rowkey : 100003   Familiy:Quilifier : name   Value : liyang   Time : 1405494141522  

    7. 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);  


    8. 取得查询结果
    不管是官网的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))
                            );
                }
            }  

  • 相关阅读:
    Hanoi塔
    采药
    进制转换(大数)
    Load Balancing with NGINX 负载均衡算法
    upstream模块实现反向代理的功能
    epoll
    在nginx启动后,如果我们要操作nginx,要怎么做呢 别增加无谓的上下文切换 异步非阻塞的方式来处理请求 worker的个数为cpu的核数 红黑树
    粘性会话 session affinity sticky session requests from the same client to be passed to the same server in a group of servers
    负载均衡 4层协议 7层协议
    A Secure Cookie Protocol 安全cookie协议 配置服务器Cookie
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5337799.html
Copyright © 2011-2022 走看看