HBase(0.96以上版本)過濾器Filter詳解及實例代碼

目錄:html

引言 -- 參數基礎正則表達式

1. 結構(Structural)過濾器--FilterListapache

2.列值過濾器--SingleColumnValueFilterapi

        2.1.第一種構造函數狀況
-- 比較的關鍵字是字符數組
數組

        2.2.第二種構造函數狀況
-- 比較的關鍵字是比較器ByteArrayComparable
ide

3.鍵值元數據函數

        3.1. 基於列族過濾數據的FamilyFilteroop

        3.2. 基於限定符Qualifier(列)過濾數據的QualifierFilter測試

        3.3. 基於列名(即Qualifier)前綴過濾數據的ColumnPrefixFilterui

        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)比較的關鍵字是一個字符數組

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

注意:

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

                        );

            }

        }  


轉載自:http://blog.csdn.net/u010967382/article/details/37653177

相關文章
相關標籤/搜索