Hbase Scan的重要引數
Scan是操作Hbase中非常常用的一個操作,雖然前面的Hbase API操作簡單的介紹了Scan的操作,但不夠詳細,由於Scan非常常用,關於其詳細的整理也是很有必要的。
Scan
HBase中的資料表通過劃分成一個個的Region來實現資料的分片,每一個Region關聯一個RowKey的範圍區間,而每一個Region中的資料,按RowKey的字典順序進行組織。
正是基於這種設計,使得HBase能夠輕鬆應對這類查詢:“指定一個RowKey的範圍區間,獲取該區間的所有記錄”, 這類查詢在HBase被稱之為Scan。
1 . 構建Scan,指定startRow與stopRow,如果未指定的話會進行全表掃描
2 . 獲取ResultScanner
3 . 遍歷查詢結果
4 . 關閉ResultScanner
public void stringFilter() throws IOException { Configuration conf = HBaseConfiguration.create(); // 獲取Table例項 HTable table = new HTable(conf, user); // 構建Scan Scan scan = new Scan(); scan = scan.setStartRow(Bytes.toBytes(startRowxxx)).setStopRow(Bytes.toBytes(StopRowxxx)); RowFilter filter = new RowFilter( CompareFilter.CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes(224382618261914241)) ); scan.setFilter(filter); // 獲取resultScanner ResultScanner scanner = table.getScanner(scan); Result result = null; // 處理結果 while ((result = scanner.next()) != null) { byte[] value = result.getValue(Bytes.toBytes(ship), Bytes.toBytes(addr)); if (value == null || value.length == 0) { continue; } System.out.println( new String(value) ); System.out.println(hello World); } // 關閉ResultScanner scanner.close(); table.close(); }
其它的設定引數
Caching: 設定一次RPC請求批量讀取的Results數量
下面的示例程式碼設定了一次讀取回來的Results數量為100:
scan.setCaching(100);
Client每一次往RegionServer傳送scan請求,都會批量拿回一批資料(由Caching決定過了每一次拿回的Results數量),然後放到本次的Result Cache中:
應用每一次讀取資料時,都是從本地的Result Cache中獲取的。如果Result Cache中的資料讀完了,則Client會再次往RegionServer傳送scan請求獲取更多的資料。
Batch: 設定每一個Result中的列的數量
下面的示例程式碼設定了每一個Result中的列的數量的限制值為3:
scan.setBatch(3);
該引數適用於一行資料過大的場景,這樣,一行資料被請求的列會被拆成多個Results返回給Client。
舉例說明如下:
假設一行資料中共有十個列:
{Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09, Col10}
假設Scan中設定的Batch為3,那麼,這一行資料將會被拆成4個Results返回:
Result1 - {Col01,Col02,Col03}Result2 - {Col04,Col05,Col06}Result3 - {Col07,Col08,Col09}Result4 - {Col10}
關於Caching引數,我們說明了是Client每一次從RegionServer側獲取到的Results的數量,上例中,一行資料被拆成了4個Results,這將會導致Caching中的計數器被減了4次。結合Caching與Batch,我們再列舉一個稍複雜的例子:
假設,Scan的引數設定如下:
final byte[] start = Bytes.toBytes(“Row1”);
final byte[] stop = Bytes.toBytes(“Row5”);
Scan scan = new Scan();
scan.withStartRow(start).withStopRow(stop);
scan.setCaching(10);
scan.setBatch(3);
待讀取的資料RowKey與所關聯的列集如下所示:
Row1: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10}
Row2: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10,Col11}
Row3: {Col01,Col02,Col03,Col04,Col05,Col06,Col07,Col08,Col09,Col10}
再回顧一下Caching與Batch的定義:
Caching: 影響一次讀取返回的Results數量。
Batch: 限定了一個Result中所包含的列的數量,如果一行資料被請求的列的數量超出Batch限制,那麼這行資料會被拆成多個Results。
那麼, Client往RegionServer第一次請求所返回的結果集如下所示:
Result1 - Row1: {Col01,Col02,Col03}
Result2 - Row1: {Col04,Col05,Col06}
Result3 - Row1: {Col07,Col08,Col09}
Result4 - Row1: {Col10}
Result5 - Row2: {Col01,Col02,Col03}
Result6 - Row2: {Col04,Col05,Col06}
Result7 - Row2: {Col07,Col08,Col09}
Result8 - Row2: {Col10,Col11}
Result9 - Row3: {Col01,Col02,Col03}
Result10 - Row3: {Col04,Col05,Col06}
Limit: 限制一次Scan操作所獲取的行的數量
同SQL語法中的limit子句,限制一次Scan操作所獲取的行的總量:
scan.setLimit(10000);
注意:Limit引數是在2.0版本中新引入的。但在2.0.0版本中,當Batch與Limit同時設定時,似乎還存在一個BUG,初步分析問題原因應該與BatchScanResultCache中的numberOfCompletedRows計數器邏輯處理有關。因此,暫時不建議同時設定這兩個引數。
CacheBlock: RegionServer側是否要快取本次Scan所涉及的HFileBlocks
scan.setCacheBlocks(true);
e) Raw Scan: 是否可以讀取到刪除標識以及被刪除但尚未被清理的資料
scan.setRaw(true);
MaxResultSize: 從記憶體佔用量的維度限制一次Scan的返回結果集
下面的示例程式碼將返回結果集的最大值設定為5MB:
scan.setMaxResultSize(5 * 1024 * 1024);
Reversed Scan: 反向掃描
普通的Scan操作是按照字典順序從小到大的順序讀取的,而Reversed Scan則恰好相反:
scan.setReversed(true);
帶Filter的Scan
Filter可以在Scan的結果集基礎之上,對返回的記錄設定更多條件值,這些條件可以與RowKey有關,可以與列名有關,也可以與列值有關,還可以將多個Filter條件組合在一起,等等。
最常用的Filter是SingleColumnValueFilter,基於它,可以實現如下類似的查詢:
“返回滿足條件{列I:D的值大於等於10}的所有行”
示例程式碼如下:
Filter豐富了HBase的查詢能力,但使用Filter之前,需要注意一點:Filter可能會導致查詢響應時延變的不可控制。因為我們無法預測,為了找到一條符合條件的記錄,背後需要掃描多少資料量,如果在有效限制了Scan範圍區間(通過設定StartRow與StopRow限制)的前提下,該問題能夠得到有效的控制。這些資訊都要求使用Filter之前應該詳細調研自己的業務資料模型。