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

  • 相关阅读:
    webIDE 第二篇博文
    前端第一天
    记昨天
    入职第四天
    入职第二天
    linux常用命令,自己总结
    一切从头开始
    在服务器上搭建SVN
    Dynamic CRM 365学习历程--JS
    Dynamic CRM 365学习历程--有关CRM的学习过程种需要注意的事项
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5337799.html
Copyright © 2011-2022 走看看