目錄:
引言 -- 參數(shù)基礎
1. 結構(Structural)過濾器--FilterList
2.列值過濾器--SingleColumnValueFilter
2.1.第一種構造函數(shù)情況 -- 比較的關鍵字是字符數(shù)組
2.2.第二種構造函數(shù)情況 -- 比較的關鍵字是比較器ByteArrayComparable
3.鍵值元數(shù)據(jù)
3.1. 基于列族過濾數(shù)據(jù)的FamilyFilter
3.2. 基于限定符Qualifier(列)過濾數(shù)據(jù)的QualifierFilter
3.3. 基于列名(即Qualifier)前綴過濾數(shù)據(jù)的ColumnPrefixFilter
3.4. 基于多個列名(即Qualifier)前綴過濾數(shù)據(jù)的MultipleColumnPrefixFilter
3.5. 基于列范圍(不是行范圍)過濾數(shù)據(jù)ColumnRangeFilter
4. RowKey
5. PageFilter
6. SkipFilter
7. Utility--FirstKeyOnlyFilter
8. 取得查詢結果
引言 -- 參數(shù)基礎
有兩個參數(shù)類在各類Filter中經常出現(xiàn),統(tǒng)一介紹下:
(1)比較運算符 CompareFilter.CompareOp
比較運算符用于定義比較關系半火,可以有以下幾類值供選擇:
EQUAL? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 相等
GREATER? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 大于
GREATER_OR_EQUAL? ? ? ? ? 大于等于
LESS? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 小于
LESS_OR_EQUAL? ? ? ? ? ? ? ? ? 小于等于
NOT_EQUAL? ? ? ? ? ? ? ? ? ? ? ? 不等于
(2)比較器? ByteArrayComparable
通過比較器可以實現(xiàn)多樣化目標匹配效果谱邪,比較器有以下子類可以使用:
BinaryComparator? ? ? ? ? ? ? 匹配完整字節(jié)數(shù)組
BinaryPrefixComparator? ? 匹配字節(jié)數(shù)組前綴
BitComparator
NullComparator
RegexStringComparator? ? 正則表達式匹配
SubstringComparator? ? ? ? 子串匹配
1. 結構(Structural)過濾器--FilterList
FilterList 代表一個過濾器鏈寝杖,它可以包含一組即將應用于目標數(shù)據(jù)集的過濾器辩撑,過濾器間具有“與” FilterList.Operator.MUST_PASS_ALL 和“或” FilterList.Operator.MUST_PASS_ONE 關系虹统。
官網實例代碼烂翰,兩個“或”關系的過濾器的寫法:
FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);? //數(shù)據(jù)只要滿足一組過濾器中的一個就可以
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)蜒简。
構造函數(shù):
(1)比較的關鍵字是一個字符數(shù)組
SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, byte[] value)
(2)比較的關鍵字是一個比較器(比較器下一小節(jié)做介紹)
SingleColumnValueFilter(byte[] family, byte[] qualifier, CompareFilter.CompareOp compareOp, ByteArrayComparable comparator)
2.1.第一種構造函數(shù)情況 -- 比較的關鍵字是字符數(shù)組
官網示例代碼蜡秽,檢查列值和字符串'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.第二種構造函數(shù)情況 -- 比較的關鍵字是比較器ByteArrayComparable
該章節(jié)主要是針對SingleColumnValueFilter的第二種構造函數(shù)使用情況做了一些舉例:
(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. 鍵值元數(shù)據(jù)
由于HBase 采用鍵值對保存內部數(shù)據(jù)田巴,鍵值元數(shù)據(jù)過濾器評估一行的鍵(ColumnFamily:Qualifiers)是否存在 , 對應前節(jié)所述值的情況。
3.1. 基于列族過濾數(shù)據(jù)的FamilyFilter
構造函數(shù):
FamilyFilter(CompareFilter.CompareOp familyCompareOp, ByteArrayComparable familyComparator)
個人實測代碼:
HTable table = HBaseDAO.getHTable("147patents");
/**
* FamilyFilter構造函數(shù)中第二個參數(shù)是ByteArrayComparable類型
* ByteArrayComparable類參見“引言-參數(shù)基礎”章節(jié)
* 下面僅以最可能用到的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(列)過濾數(shù)據(jù)的QualifierFilter
構造函數(shù):
QualifierFilter(CompareFilter.CompareOp op, ByteArrayComparable qualifierComparator)
個人實測代碼:
HTable table = HBaseDAO.getHTable("147patents");
/**
* QualifierFilter構造函數(shù)中第二個參數(shù)是ByteArrayComparable類型
* ByteArrayComparable類有以下子類可以使用:
* *******************************************
* BinaryComparator? 匹配完整字節(jié)數(shù)組,
* BinaryPrefixComparator? 匹配開始的部分字節(jié)數(shù)組,
* 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云稚,過濾結果為所有行的該列數(shù)據(jù)
);
Scan scan = new Scan();
scan.setFilter(ff1);
ResultScanner rs = table.getScanner(scan);
說明:
一旦涉及到列(Qualifier)隧饼,HBase就只認大寫字母了!
該過濾器應該比FamilyFilter更常用静陈!
3.3. 基于列名(即Qualifier)前綴過濾數(shù)據(jù)的ColumnPrefixFilter? ( 該功能用QualifierFilter也能實現(xiàn) )
構造函數(shù):
ColumnPrefixFilter(byte[] prefix)
注意:
一個列名是可以出現(xiàn)在多個列族中的燕雁,該過濾器將返回所有列族中匹配的列诞丽。
官網示例代碼,查找所有"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打頭的列的數(shù)據(jù)
ColumnPrefixFilter ff1 = new ColumnPrefixFilter(Bytes.toBytes("BELONG"));
Scan scan = new Scan();
scan.setFilter(ff1);
ResultScanner rs = table.getScanner(scan);
3.4. 基于多個列名(即Qualifier)前綴過濾數(shù)據(jù)的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打頭的列的數(shù)據(jù)
MultipleColumnPrefixFilter ff = new MultipleColumnPrefixFilter(prefixes);
Scan scan = new Scan();
scan.setFilter(ff);
ResultScanner rs = table.getScanner(scan);
3.5. 基于列范圍(不是行范圍)過濾數(shù)據(jù)ColumnRangeFilter
說明:
可用于獲得一個范圍的列捏浊,例如懂衩,如果你的一行中有百萬個列,但是你只希望查看列名為bbbb到dddd的范圍
該方法從 HBase 0.92 版本開始引入
一個列名是可以出現(xiàn)在多個列族中的金踪,該過濾器將返回所有列族中匹配的列
構造函數(shù):
ColumnRangeFilter(byte[] minColumn, boolean minColumnInclusive, byte[] maxColumn, boolean maxColumnInclusive)
參數(shù)解釋:
minColumn - 列范圍的最小值浊洞,如果為空,則沒有下限胡岔;
minColumnInclusive - 列范圍是否包含minColumn 法希;
maxColumn - 列范圍最大值,如果為空靶瘸,則沒有上限苫亦;
maxColumnInclusive - 列范圍是否包含maxColumn 。
官網示例代碼奕锌,查找列名在"bbbb"到"dddd"范圍的數(shù)據(jù):
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打頭的范圍的數(shù)據(jù)著觉,實際返回類似CREATOR村生、CREATE_TIME惊暴、CHANNEL_CODE等列的數(shù)據(jù)
ColumnRangeFilter ff = new ColumnRangeFilter(startColumn, true, endColumn, true);
Scan scan = new Scan();
scan.setFilter(ff);
ResultScanner rs = table.getScanner(scan);
4. RowKey
當需要根據(jù)行鍵特征查找一個范圍的行數(shù)據(jù)時,使用Scan的startRow和stopRow會更高效趁桃,但是辽话,startRow和stopRow只能匹配行鍵的開始字符,而不能匹配中間包含的字符:
byte[] startColumn = Bytes.toBytes("aaa");
byte[] endColumn = Bytes.toBytes("bbb");
Scan scan = new Scan(startColumn,endColumn);
當需要針對行鍵進行更復雜的過濾時卫病,可以使用RowFilter:
構造函數(shù):
RowFilter(CompareFilter.CompareOp rowCompareOp, ByteArrayComparable rowComparator)
參數(shù)解釋參見“引言-參數(shù)基礎”章節(jié)油啤。
個人實測代碼:
HTable table = HBaseDAO.getHTable("147patents");
/**
* rowkey格式為:創(chuàng)建日期_發(fā)布日期_ID_TITLE
* 目標:查找? 發(fā)布日期? 為? 2013-07-16? 的數(shù)據(jù)
*/
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參數(shù)分別為GREATER_OR_EQUAL和LESS_OR_EQUAL),和SubstringComparator蟀苛,過濾找出指定發(fā)布時間范圍內的數(shù)據(jù)益咬,但結果比較意外,不是預想的數(shù)據(jù)帜平,估計比較運算符GREATER_OR_EQUAL和LESS_OR_EQUAL和比較器SubstringComparator組合使用效果不太好幽告,慎用。
5.PageFilter
指定頁面行數(shù)裆甩,返回對應行數(shù)的結果集冗锁。
需要注意的是,該過濾器并不能保證返回的結果行數(shù)小于等于指定的頁面行數(shù)嗤栓,因為過濾器是分別作用到各個region server的冻河,它只能保證當前region返回的結果行數(shù)不超過指定頁面行數(shù)箍邮。
構造函數(shù):
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());
}
}
注意:
由于該過濾器并不能保證返回的結果行數(shù)小于等于指定的頁面行數(shù)叨叙,所以更好的返回指定行數(shù)的辦法是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
根據(jù)整行中的每個列來做過濾,只要存在一列不滿足條件擂错,整行都被過濾掉廷蓉。
例如,如果一行中的所有列代表的是不同物品的重量马昙,則真實場景下這些數(shù)值都必須大于零桃犬,我們希望將那些包含任意列值為0的行都過濾掉。
在這個情況下行楞,我們結合ValueFilter和SkipFilter共同實現(xiàn)該目的:
scan.setFilter(new SkipFilter(new ValueFilter(CompareOp.NOT_EQUAL,new BinaryComparator(Bytes.toBytes(0))));
構造函數(shù):
SkipFilter(Filter filter)
個人實測代碼:
目前的數(shù)據(jù):
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
執(zhí)行以下代碼:
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的值攒暇,可以用于高效的執(zhí)行行數(shù)統(tǒng)計操作。
估計實戰(zhàn)意義不大子房。
構造函數(shù):
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))
);
}
}