1. 程式人生 > 實用技巧 >【轉載】HBase基本資料操作詳解【完整版,絕對精品】

【轉載】HBase基本資料操作詳解【完整版,絕對精品】


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

概述 對於建表,和RDBMS類似,HBase也有namespace的概念,可以指定表空間建立表,也可以直接建立表,進入default表空間。 對於資料操作,HBase支援四類主要的資料操作,分別是:
  • Put:增加一行,修改一行;
  • Delete:刪除一行,刪除指定列族,刪除指定column的多個版本,刪除指定column的制定版本等;
  • Get:獲取指定行的所有資訊,獲取指定行和指定列族的所有colunm,獲取指定column,獲取指定column的幾個版本,獲取指定column的指定版本等;
  • Scan:獲取所有行,獲取指定行鍵範圍的行,獲取從某行開始的幾行,獲取滿足過濾條件的行等。
這四個類都是org.apache.hadoop.hbase.client的子類,可以到官網API去檢視詳細資訊,本文僅總結常用方法,力爭讓讀者用20%的時間掌握80%的常用功能。
目錄 1.名稱空間Namespace 2.建立表 3.刪除表 4.修改表 5.新增、更新資料Put 6.刪除資料Delete 7.獲取單行Get 8.獲取多行Scan
1. 名稱空間Namespace
在關係資料庫系統中,名稱空間namespace指的是一個表的邏輯分組,同一組中的表有類似的用途。名稱空間的概念為即將到來
的多租戶特性打下基礎:

  • 配額管理(Quota Management (HBASE-8410)):限制一個namespace可以使用的資源,資源包括region和table等;
  • 名稱空間安全管理(Namespace Security Administration (HBASE-9206)):提供了另一個層面的多租戶安全管理;
  • Region伺服器組(Region server groups (HBASE-6721)):一個名稱空間或一張表,可以被固定到一組regionservers上,從而保證了資料隔離性。

1.1.名稱空間管理 名稱空間可以被建立、移除、修改。 表和名稱空間的隸屬關係
在在建立表時決定,通過以下格式指定:
<namespace>:<table>

Example:hbase shell中建立名稱空間、建立名稱空間中的表、移除名稱空間、修改名稱空間
#Create a namespace
create_namespace 'my_ns'
            
#create my_table in my_ns namespace
create 'my_ns:my_table', 'fam'
          
#drop namespace
drop_namespace 'my_ns'
          
#alter namespace
alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
        

1.2. 預定義的名稱空間 有兩個系統內建的預定義名稱空間:
  • hbase:系統名稱空間,用於包含hbase的內部表
  • default所有未指定名稱空間的表都自動進入該名稱空間
Example:指定名稱空間和預設名稱空間
#namespace=foo and table qualifier=bar
create 'foo:bar', 'fam'

namespace=default and table qualifier=bar

create 'bar', 'fam'


2.建立表 廢話不多說,直接上樣板程式碼,程式碼後再說明注意事項和知識點:
Configurationconf=HBaseConfiguration.create(); HBaseAdminadmin=newHBaseAdmin(conf); //createnamespacenamed"my_ns" admin.createNamespace(NamespaceDescriptor.create("my_ns").build()); //createtableDesc,withnamespacename"my_ns"andtablename"mytable" HTableDescriptortableDesc=newHTableDescriptor(TableName.valueOf("my_ns:mytable")); tableDesc.setDurability(Durability.SYNC_WAL);
//addacolumnfamily"mycf" HColumnDescriptorhcd=newHColumnDescriptor("mycf"); tableDesc.addFamily(hcd); admin.createTable(tableDesc); admin.close();

關鍵知識點:
  1. 必須將HBase叢集的hbase-site.xml檔案新增進工程的classpath中,或者通過Configuration物件設定相關屬性,否則程式獲取不到叢集相關資訊,也就無法找到叢集,執行程式時會報錯;
  2. HTableDescriptortableDesc=newHTableDescriptor(TableName.valueOf("my_ns:mytable"))程式碼是描述表mytable,並將mytable放到了my_ns名稱空間中,前提是該名稱空間已存在,如果指定的是不存在名稱空間,則會報org.apache.hadoop.hbase.NamespaceNotFoundException;
  3. 名稱空間一般在建模階段通過命令列建立,在java程式碼中通過admin.createNamespace(NamespaceDescriptor.create("my_ns").build())建立的機會不多;
  4. 建立HBaseAdmin物件時就已經建立了客戶端程式與HBase叢集的connection,所以在程式執行完成後,務必通過admin.close()關閉connection;
  5. 可以通過HTableDescriptor物件設定表的特性,比如:通過tableDesc.setMaxFileSize(512)設定一個region中的store檔案的最大size,當一個region中的最大store檔案達到這個size時,region就開始分裂;通過tableDesc.setMemStoreFlushSize(512)設定region記憶體中的memstore的最大值,當memstore達到這個值時,開始往磁碟中刷資料。更多特性請自行查閱官網API;
  6. 可以通過HColumnDescriptor物件設定列族的特性,比如:通過hcd.setTimeToLive(5184000)設定資料儲存的最長時間;通過hcd.setInMemory(true)設定資料儲存在記憶體中以提高響應速度;通過hcd.setMaxVersions(10)設定資料儲存的最大版本數;通過hcd.setMinVersions(5)設定資料儲存的最小版本數(配合TimeToLive使用)。更多特性請自行查閱官網API;
  7. 資料的版本數只能通過HColumnDescriptor物件設定,不能通過HTableDescriptor物件設定;
  8. 由於HBase的資料是先寫入記憶體,資料累計達到記憶體閥值時才往磁碟中flush資料,所以,如果在資料還沒有flush進硬碟時,regionserver down掉了,記憶體中的資料將丟失。要想解決這個場景的問題就需要用到WAL(Write-Ahead-Log),tableDesc.setDurability(Durability.SYNC_WAL)就是設定寫WAL日誌的級別,示例中設定的是同步寫WAL,該方式安全性較高,但無疑會一定程度影響效能,請根據具體場景選擇使用;
  9. setDurability(Durability d)方法可以在相關的三個物件中使用,分別是:HTableDescriptor,Delete,Put(其中Delete和Put的該方法都是繼承自父類org.apache.hadoop.hbase.client.Mutation)。分別針對表、插入操作、刪除操作設定WAL日誌寫入級別。需要注意的是,Delete和Put並不會繼承Table的Durability級別(已實測驗證)。Durability是一個列舉變數,可選值參見4.2節。如果不通過該方法指定WAL日誌級別,則為預設USE_DEFAULT級別。

3.刪除表 刪除表沒建立表那麼多學問,直接上程式碼: Configurationconf=HBaseConfiguration.create(); HBaseAdminadmin=newHBaseAdmin(conf); Stringtablename="my_ns:mytable"; if(admin.tableExists(tablename)){ try{ admin.disableTable(tablename); admin.deleteTable(tablename); }catch(Exceptione){ //TODO:handleexception e.printStackTrace(); } } admin.close();
說明:刪除表前必須先disable表。
4.修改表 4.1.例項程式碼 (1)刪除列族、新增列族 修改之前,四個列族: hbase(main):014:0> describe 'rd_ns:itable' DESCRIPTION ENABLED 'rd_ns:itable', {NAME => 'info', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', V true ERSIONS => '10', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => 'newcf', DATA_BLOCK_ENCODING => 'NONE ', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647', MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'tr ue'}, {NAME => 'note', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '10', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => 'sysinfo', DATA_BLOCK_ENCODING => 'NONE', BLOOM FILTER => 'ROW', REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647', MIN_VERS IONS => '0', KEEP_DELETED_CELLS => 'true', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'} 1 row(s) in 0.0450 seconds
修改表,刪除三個列族,新增一個列族,程式碼如下: Configurationconf=HBaseConfiguration.create(); HBaseAdminadmin=newHBaseAdmin(conf); Stringtablename="rd_ns:itable"; if(admin.tableExists(tablename)){ try{ admin.disableTable(tablename); //gettheTableDescriptoroftargettable HTableDescriptornewtd=admin.getTableDescriptor(Bytes.toBytes("rd_ns:itable")); //remove3uselesscolumnfamilies newtd.removeFamily(Bytes.toBytes("note")); newtd.removeFamily(Bytes.toBytes("newcf")); newtd.removeFamily(Bytes.toBytes("sysinfo")); //createHColumnDescriptorfornewcolumnfamily HColumnDescriptornewhcd=newHColumnDescriptor("action_log"); newhcd.setMaxVersions(10); newhcd.setKeepDeletedCells(true); //addthenewcolumnfamily(HColumnDescriptor)toHTableDescriptor newtd.addFamily(newhcd); //modifytargettablestruture admin.modifyTable(Bytes.toBytes("rd_ns:itable"),newtd); admin.enableTable(tablename); }catch(Exceptione){ //TODO:handleexception e.printStackTrace(); } } admin.close();


修改之後: hbase(main):015:0> describe 'rd_ns:itable' DESCRIPTION ENABLED 'rd_ns:itable', {NAME => 'action_log', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => true '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647', MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'tr ue', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => 'info', DATA_BLOCK_ENCODING => ' NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '10', COMPRESSION => 'NONE', MIN_VERSIONS => ' 0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'} 1 row(s) in 0.0400 seconds
邏輯很簡單:
  1. 通過admin.getTableDescriptor(Bytes.toBytes("rd_ns:itable"))取得目標表的描述物件,應該就是取得指向該物件的指標了;
  2. 修改目標表描述物件;
  3. 通過admin.modifyTable(Bytes.toBytes("rd_ns:itable"),newtd)將修改後的描述物件應用到目標表。

(2)修改現有列族的屬性(setMaxVersions) Configurationconf=HBaseConfiguration.create(); HBaseAdminadmin=newHBaseAdmin(conf); Stringtablename="rd_ns:itable"; if(admin.tableExists(tablename)){ try{ admin.disableTable(tablename);
//gettheTableDescriptoroftargettable HTableDescriptorhtd=admin.getTableDescriptor(Bytes.toBytes("rd_ns:itable")); HColumnDescriptorinfocf=htd.getFamily(Bytes.toBytes("info")); infocf.setMaxVersions(100);
//modifytargettablestruture admin.modifyTable(Bytes.toBytes("rd_ns:itable"),htd); admin.enableTable(tablename); }catch(Exceptione){ //TODO:handleexception e.printStackTrace(); } } admin.close();


5.新增、更新資料Put 5.1.常用建構函式: (1)指定行鍵 public Put(byte[] row) 引數:row 行鍵
(2)指定行鍵和時間戳 public Put(byte[] row,long ts) 引數:row 行鍵,ts 時間戳
(3)從目標字串中提取子串,作為行鍵 Put(byte[] rowArray, int rowOffset, int rowLength)
(4)從目標字串中提取子串,作為行鍵,並加上時間戳
Put(byte[] rowArray, int rowOffset, int rowLength, long ts)
5.2.常用方法: (1)指定列族、限定符,新增值 add(byte[] family, byte[] qualifier, byte[] value)

(2)指定列族、限定符、時間戳,新增值 add(byte[] family, byte[] qualifier, long ts, byte[] value)
(3)設定寫WAL(Write-Ahead-Log)的級別 public void setDurability(Durability d)
引數是一個列舉值,可以有以下幾種選擇:
  • ASYNC_WAL : 當資料變動時,非同步寫WAL日誌
  • SYNC_WAL : 當資料變動時,同步寫WAL日誌
  • FSYNC_WAL : 當資料變動時,同步寫WAL日誌,並且,強制將資料寫入磁碟
  • SKIP_WAL : 不寫WAL日誌
  • USE_DEFAULT : 使用HBase全域性預設的WAL寫入級別,即SYNC_WAL

5.3.例項程式碼 (1)插入行 Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable");
Putput=newPut(Bytes.toBytes("100001")); put.add(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("lion")); put.add(Bytes.toBytes("info"),Bytes.toBytes("address"),Bytes.toBytes("shangdi")); put.add(Bytes.toBytes("info"),Bytes.toBytes("age"),Bytes.toBytes("30")); put.setDurability(Durability.SYNC_WAL);

table.put(put); table.close();

(2)更新行 Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable"); Putput=newPut(Bytes.toBytes("100001")); put.add(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("lee")); put.add(Bytes.toBytes("info"),Bytes.toBytes("address"),Bytes.toBytes("longze")); put.add(Bytes.toBytes("info"),Bytes.toBytes("age"),Bytes.toBytes("31")); put.setDurability(Durability.SYNC_WAL);

table.put(put); table.close();
注意:
  1. Put的建構函式都需要指定行鍵,如果是全新的行鍵,則新增一行;如果是已有的行鍵,則更新現有行。
  2. 建立Put物件及put.add過程都是在構建一行的資料,建立Put物件時相當於建立了行物件,add的過程就是往目標行裡新增cell,直到table.put才將資料插入表格;
  3. 以上程式碼建立Put物件用的是建構函式1,也可用建構函式2,第二個引數是時間戳;
  4. Put還有別的建構函式,請查閱官網API。

(3)從目標字串中提取子串,作為行鍵,構建Put Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable"); Putput=newPut(Bytes.toBytes("100001_100002"),7,6); put.add(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("show")); put.add(Bytes.toBytes("info"),Bytes.toBytes("address"),Bytes.toBytes("caofang")); put.add(Bytes.toBytes("info"),Bytes.toBytes("age"),Bytes.toBytes("30")); table.put(put); table.close();

注意,關於:Putput=newPut(Bytes.toBytes("100001_100002"),7,6)
  1. 第二個引數是偏移量,也就是行鍵從第一個引數的第幾個字元開始擷取;
  2. 第三個引數是擷取長度;
  3. 這個程式碼實際是從 100001_100002 中截取了100002子串作為目標行的行鍵。

6.刪除資料Delete Delete類用於刪除表中的一行資料,通過HTable.delete來執行該動作。 在執行Delete操作時,HBase並不會立即刪除資料,而是對需要刪除的資料打上一個“墓碑”標記,直到當Storefile合併時,再清除這些被標記上“墓碑”的資料。 如果希望刪除整行,用行鍵來初始化一個Delete物件即可。如果希望進一步定義刪除的具體內容,可以使用以下這些Delete物件的方法:
  • 為了刪除指定的列族,可以使用deleteFamily
  • 為了刪除指定列的多個版本,可以使用deleteColumns
  • 為了刪除指定列的指定版本,可以使用deleteColumn,這樣的話就只會刪除版本號(時間戳)與指定版本相同的列。如果不指定時間戳,預設只刪除最新的版本
下面詳細說明建構函式和常用方法: 6.1.建構函式 (1)指定要刪除的行鍵 Delete(byte[] row) 刪除行鍵指定行的資料。 如果沒有進一步的操作,使用該建構函式將刪除行鍵指定的行中所有列族中所有列的所有版本
(2)指定要刪除的行鍵和時間戳 Delete(byte[] row, long timestamp) 刪除行鍵和時間戳共同確定行的資料。 如果沒有進一步的操作,使用該建構函式將刪除行鍵指定的行中,所有列族中所有列的時間戳小於等於指定時間戳的資料版本注意:該時間戳僅僅和刪除行有關,如果需要進一步指定列族或者列,你必須分別為它們指定時間戳。
(3)給定一個字串,目標行鍵的偏移,擷取的長度 Delete(byte[] rowArray, int rowOffset, int rowLength)
(4)給定一個字串,目標行鍵的偏移,擷取的長度,時間戳
Delete(byte[] rowArray, int rowOffset, int rowLength, long ts)
6.2.常用方法
  • Delete deleteColumn(byte[] family, byte[] qualifier) 刪除指定列的最新版本的資料。
  • Delete deleteColumns(byte[] family, byte[] qualifier) 刪除指定列的所有版本的資料。
  • Delete deleteColumn(byte[] family, byte[] qualifier, longtimestamp) 刪除指定列的指定版本的資料。
  • Delete deleteColumns(byte[] family, byte[] qualifier, longtimestamp) 刪除指定列的,時間戳小於等於給定時間戳所有版本的資料。

  • Delete deleteFamily(byte[] family) 刪除指定列族的所有列的所有版本資料。
  • Delete deleteFamily(byte[] family, long timestamp) 刪除指定列族的所有列中時間戳小於等於指定時間戳的所有資料。
  • Delete deleteFamilyVersion(byte[] family, long timestamp) 刪除指定列族中所有列的時間戳等於指定時間戳的版本資料。

  • voidsetTimestamp(long timestamp) 為Delete物件設定時間戳。

6.3.例項程式碼 (1)刪除整行的所有列族、所有行、所有版本 Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable"); Deletedelete=newDelete(Bytes.toBytes("000")); table.delete(delete); table.close();

(2)刪除指定列的最新版本 以下是刪除之前的資料,注意看100003行的info:address,這是該列最新版本的資料,值是caofang1,在這之前的版本值是caofang: hbase(main):007:0> scan 'rd_ns:leetable' ROW COLUMN+CELL 100001 column=info:address, timestamp=1405304843114, value=longze 100001 column=info:age, timestamp=1405304843114, value=31 100001 column=info:name, timestamp=1405304843114, value=leon 100002 column=info:address, timestamp=1405305471343, value=caofang 100002 column=info:age, timestamp=1405305471343, value=30 100002 column=info:name, timestamp=1405305471343, value=show 100003 column=info:address, timestamp=1405390959464, value=caofang1 100003 column=info:age, timestamp=1405390959464, value=301 100003 column=info:name, timestamp=1405390959464, value=show1 3 row(s) in 0.0270 seconds
執行以下程式碼: Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable");
Deletedelete=newDelete(Bytes.toBytes("100003")); delete.deleteColumn(Bytes.toBytes("info"),Bytes.toBytes("address")); table.delete(delete); table.close();

然後檢視資料,發現100003列的info:address列的值顯示為前一個版本的caofang了!其餘值均不變: hbase(main):008:0> scan 'rd_ns:leetable' ROW COLUMN+CELL 100001 column=info:address, timestamp=1405304843114, value=longze 100001 column=info:age, timestamp=1405304843114, value=31 100001 column=info:name, timestamp=1405304843114, value=leon 100002 column=info:address, timestamp=1405305471343, value=caofang 100002 column=info:age, timestamp=1405305471343, value=30 100002 column=info:name, timestamp=1405305471343, value=show 100003 column=info:address, timestamp=1405390728175, value=caofang 100003 column=info:age, timestamp=1405390959464, value=301 100003 column=info:name, timestamp=1405390959464, value=show1 3 row(s) in 0.0560 seconds
(3)刪除指定列的所有版本 接以上場景,執行以下程式碼: Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable");
Deletedelete=newDelete(Bytes.toBytes("100003")); delete.deleteColumns(Bytes.toBytes("info"),Bytes.toBytes("address")); table.delete(delete); table.close();

然後我們會發現,100003行的整個info:address列都沒了: hbase(main):009:0> scan 'rd_ns:leetable' ROW COLUMN+CELL 100001 column=info:address, timestamp=1405304843114, value=longze 100001 column=info:age, timestamp=1405304843114, value=31 100001 column=info:name, timestamp=1405304843114, value=leon 100002 column=info:address, timestamp=1405305471343, value=caofang 100002 column=info:age, timestamp=1405305471343, value=30 100002 column=info:name, timestamp=1405305471343, value=show 100003 column=info:age, timestamp=1405390959464, value=301 100003 column=info:name, timestamp=1405390959464, value=show1 3 row(s) in 0.0240 seconds
(4)刪除指定列族中所有列的時間戳等於指定時間戳的版本資料 為了演示效果,我已經向100003行的info:address列新插入一條資料 hbase(main):010:0> scan 'rd_ns:leetable' ROW COLUMN+CELL 100001 column=info:address, timestamp=1405304843114, value=longze 100001 column=info:age, timestamp=1405304843114, value=31 100001 column=info:name, timestamp=1405304843114, value=leon 100002 column=info:address, timestamp=1405305471343, value=caofang 100002 column=info:age, timestamp=1405305471343, value=30 100002 column=info:name, timestamp=1405305471343, value=show 100003 column=info:address, timestamp=1405391883886, value=shangdi 100003 column=info:age, timestamp=1405390959464, value=301 100003 column=info:name, timestamp=1405390959464, value=show1 3 row(s) in 0.0250 seconds
現在,我們的目的是刪除info列族中,時間戳為1405390959464的所有列資料: Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable"); Deletedelete=newDelete(Bytes.toBytes("100003")); delete.deleteFamilyVersion(Bytes.toBytes("info"),1405390959464L); table.delete(delete); table.close();

hbase(main):011:0> scan 'rd_ns:leetable' ROW COLUMN+CELL 100001 column=info:address, timestamp=1405304843114, value=longze 100001 column=info:age, timestamp=1405304843114, value=31 100001 column=info:name, timestamp=1405304843114, value=leon 100002 column=info:address, timestamp=1405305471343, value=caofang 100002 column=info:age, timestamp=1405305471343, value=30 100002 column=info:name, timestamp=1405305471343, value=show 100003 column=info:address, timestamp=1405391883886, value=shangdi 100003 column=info:age, timestamp=1405390728175, value=30 100003 column=info:name, timestamp=1405390728175, value=show 3 row(s) in 0.0250 seconds
可以看到,100003行的info列族,已經不存在時間戳為1405390959464的資料,比它更早版本的資料被查詢出來,而info列族中時間戳不等於1405390959464的address列,不受該delete的影響
7.獲取單行Get 如果希望獲取整行資料,用行鍵初始化一個Get物件就可以,如果希望進一步縮小獲取的資料範圍,可以使用Get物件的以下方法:
  • 如果希望取得指定列族的所有列資料,使用addFamily新增所有的目標列族即可;
  • 如果希望取得指定列的資料,使用addColumn新增所有的目標列即可;
  • 如果希望取得目標列的指定時間戳範圍的資料版本,使用setTimeRange
  • 如果僅希望獲取目標列的指定時間戳版本,則使用setTimestamp
  • 如果希望限制每個列返回的版本數,使用setMaxVersions
  • 如果希望新增過濾器,使用setFilter
下面詳細描述建構函式及常用方法: 7.1.建構函式 Get的建構函式很簡單,只有一個建構函式:Get(byte[] row) 引數是行鍵。
7.2.常用方法
  • GetaddFamily(byte[] family) 指定希望獲取的列族
  • GetaddColumn(byte[] family, byte[] qualifier) 指定希望獲取的列
  • GetsetTimeRange(long minStamp, long maxStamp) 設定獲取資料的時間戳範圍
  • GetsetTimeStamp(long timestamp) 設定獲取資料的時間戳
  • GetsetMaxVersions(int maxVersions) 設定獲取資料的版本數
  • GetsetMaxVersions() 設定獲取資料的所有版本
  • GetsetFilter(Filter filter) 為Get物件新增過濾器,過濾器詳解請參見:http://blog.csdn.net/u010967382/article/details/37653177
  • voidsetCacheBlocks(boolean cacheBlocks) 設定該Get獲取的資料是否快取在記憶體中

7.3.實測程式碼 測試表的所有資料: hbase(main):016:0> scan 'rd_ns:leetable' ROW COLUMN+CELL 100001 column=info:address, timestamp=1405304843114, value=longze 100001 column=info:age, timestamp=1405304843114, value=31 100001 column=info:name, timestamp=1405304843114, value=leon 100002 column=info:address, timestamp=1405305471343, value=caofang 100002 column=info:age, timestamp=1405305471343, value=30 100002 column=info:name, timestamp=1405305471343, value=show 100003 column=info:address, timestamp=1405407883218, value=qinghe 100003 column=info:age, timestamp=1405407883218, value=28 100003 column=info:name, timestamp=1405407883218, value=shichao 3 row(s) in 0.0250 seconds (1)獲取行鍵指定行的所有列族、所有列最新版本資料 Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable"); Getget=newGet(Bytes.toBytes("100003")); Resultr=table.get(get); for(Cellcell:r.rawCells()){ System.out.println( "Rowkey:"+Bytes.toString(r.getRow())+ "Familiy:Quilifier:"+Bytes.toString(CellUtil.cloneQualifier(cell))+ "Value:"+Bytes.toString(CellUtil.cloneValue(cell)) ); } table.close();
程式碼輸出: Rowkey:100003Familiy:Quilifier:addressValue:qinghe Rowkey:100003Familiy:Quilifier:ageValue:28 Rowkey:100003Familiy:Quilifier:nameValue:shichao

(2)獲取行鍵指定行中,指定列的最新版本資料 Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable"); Getget=newGet(Bytes.toBytes("100003")); get.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name")); Resultr=table.get(get); for(Cellcell:r.rawCells()){ System.out.println( "Rowkey:"+Bytes.toString(r.getRow())+ "Familiy:Quilifier:"+Bytes.toString(CellUtil.cloneQualifier(cell))+ "Value:"+Bytes.toString(CellUtil.cloneValue(cell)) ); } table.close();
程式碼輸出: Rowkey:100003Familiy:Quilifier:nameValue:shichao

(3)獲取行鍵指定的行中,指定時間戳的資料 Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:leetable"); Getget=newGet(Bytes.toBytes("100003")); get.setTimeStamp(1405407854374L); Resultr=table.get(get); for(Cellcell:r.rawCells()){ System.out.println( "Rowkey:"+Bytes.toString(r.getRow())+ "Familiy:Quilifier:"+Bytes.toString(CellUtil.cloneQualifier(cell))+ "Value:"+Bytes.toString(CellUtil.cloneValue(cell)) ); } table.close();

程式碼輸出了上面scan命令輸出中沒有展示的歷史資料: Rowkey:100003Familiy:Quilifier:addressValue:huangzhuang Rowkey:100003Familiy:Quilifier:ageValue:32 Rowkey:100003Familiy:Quilifier:nameValue:lily

(4)獲取行鍵指定的行中,所有版本的資料
Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:itable"); Getget=newGet(Bytes.toBytes("100003")); get.setMaxVersions(); Resultr=table.get(get); for(Cellcell: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();

程式碼輸出: Rowkey:100003Familiy:Quilifier:addressValue:xierqiTime:1405417500485 Rowkey:100003Familiy:Quilifier:addressValue:shangdiTime:1405417477465 Rowkey:100003Familiy:Quilifier:addressValue:longzeTime:1405417448414 Rowkey:100003Familiy:Quilifier:ageValue:29Time:1405417500485 Rowkey:100003Familiy:Quilifier:ageValue:30Time:1405417477465 Rowkey:100003Familiy:Quilifier:ageValue:31Time:1405417448414 Rowkey:100003Familiy:Quilifier:nameValue:leonTime:1405417500485 Rowkey:100003Familiy:Quilifier:nameValue:leeTime:1405417477465 Rowkey:100003Familiy:Quilifier:nameValue:lionTime:1405417448414

注意: 能輸出多版本資料的前提是當前列族能儲存多版本資料,列族可以儲存的資料版本數通過HColumnDescriptor的setMaxVersions(Int)方法設定。
8.獲取多行Scan Scan物件可以返回滿足給定條件的多行資料。如果希望獲取所有的行,直接初始化一個Scan物件即可。如果希望限制掃描的行範圍,可以使用以下方法:
  • 如果希望獲取指定列族的所有列,可使用addFamily方法來新增所有希望獲取的列族
  • 如果希望獲取指定列,使用addColumn方法來新增所有列
  • 通過setTimeRange方法設定獲取列的時間範圍
  • 通過setTimestamp方法指定具體的時間戳,只返回該時間戳的資料
  • 通過setMaxVersions方法設定最大返回的版本數
  • 通過setBatch方法設定返回資料的最大行數
  • 通過setFilter方法為Scan物件新增過濾器,過濾器詳解請參見:http://blog.csdn.net/u010967382/article/details/37653177
  • Scan的結果資料是可以快取在記憶體中的,可以通過getCaching()方法來檢視當前設定的快取條數,也可以通過setCaching(int caching)來設定快取在記憶體中的行數,快取得越多,以後查詢結果越快,同時也消耗更多記憶體。此外,通過setCacheBlocks方法設定是否快取Scan的結果資料塊,預設為true
  • 我們可以通過setMaxResultSize(long)方法來設定Scan返回的結果行數。

下面是官網文件中的一個入門示例:假設表有幾行鍵值為 "row1", "row2", "row3",還有一些行有鍵值 "abc1", "abc2", 和 "abc3",目標是返回"row"打頭的行:
HTable htable = ... // instantiate HTable Scan scan = new Scan(); scan.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("attr")); scan.setStartRow( Bytes.toBytes("row")); // start key is inclusive scan.setStopRow( Bytes.toBytes("row" + (char)0)); // stop key is exclusive ResultScanner rs = htable.getScanner(scan); try { for (Result r = rs.next(); r != null; r = rs.next()) { // process result... } finally { rs.close(); // always close the ResultScanner! }

8.1.常用建構函式 (1)建立掃描所有行的Scan Scan()
(2)建立Scan,從指定行開始掃描, Scan(byte[] startRow) 引數:startRow行鍵 注意:如果指定行不存在,從下一個最近的行開始

(3)建立Scan,指定起止行 Scan(byte[] startRow, byte[] stopRow) 引數:startRow起始行,stopRow終止行 注意startRow <= 結果集 <stopRow
(4)建立Scan,指定起始行和過濾器 Scan(byte[] startRow, Filter filter) 引數:startRow起始行,filter過濾器 注意:過濾器的功能和構造參見http://blog.csdn.net/u010967382/article/details/37653177
8.2.常用方法
  • Scan setStartRow(byte[] startRow) 設定Scan的開始行,預設結果集包含該行。如果希望結果集不包含該行,可以在行鍵末尾加上0。
  • Scan setStopRow(byte[] stopRow)設定Scan的結束行,預設結果集不包含該行。如果希望結果集包含該行,可以在行鍵末尾加上0。
  • Scan setTimeRange(long minStamp, long maxStamp)掃描指定時間範圍的資料
  • Scan setTimeStamp(long timestamp) 掃描指定時間的資料
  • Scan addColumn(byte[] family, byte[] qualifier) 指定掃描的列
  • Scan addFamily(byte[] family) 指定掃描的列族
  • Scan setFilter(Filter filter) 為Scan設定過濾器
  • Scan setReversed(boolean reversed) 設定Scan的掃描順序,預設是正向掃描(false),可以設定為逆向掃描(true)。注意:該方法0.98版本以後才可用!!
  • Scan setMaxVersions() 獲取所有版本的資料
  • Scan setMaxVersions(int maxVersions) 設定獲取的最大版本數
  • void setCaching(int caching) 設定快取在記憶體中的行數,快取得越多,以後查詢結果越快,同時也消耗更多記憶體
  • voidsetRaw(boolean raw) 啟用或者禁用raw模式。如果raw模式被啟用,Scan將返回所有已經被打上刪除標記但尚未被真正刪除的資料。該功能僅用於激活了KEEP_DELETED_ROWS的列族,即列族開啟了hcd.setKeepDeletedCells(true)。Scan啟用raw模式後,就不能指定任意的列,否則會報錯

Enable/disable "raw" mode for this scan. If "raw" is enabled the scan will return all delete marker and deleted rows that have not been collected, yet. This is mostly useful for Scan oncolumn familiesthat have KEEP_DELETED_ROWS enabled. It is an error to specify any column when "raw" is set. hcd.setKeepDeletedCells(true);
8.3.實測程式碼 (1)掃描表中的所有行的最新版本資料 Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:itable"); Scans=newScan(); ResultScannerrs=table.getScanner(s); for(Resultr:rs){ for(Cellcell: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();
程式碼輸出: Rowkey:100001Familiy:Quilifier:addressValue:anywhereTime:1405417403438 Rowkey:100001Familiy:Quilifier:ageValue:24Time:1405417403438 Rowkey:100001Familiy:Quilifier:nameValue:zhangtaoTime:1405417403438 Rowkey:100002Familiy:Quilifier:addressValue:shangdiTime:1405417426693 Rowkey:100002Familiy:Quilifier:ageValue:28Time:1405417426693 Rowkey:100002Familiy:Quilifier:nameValue:shichaoTime:1405417426693 Rowkey:100003Familiy:Quilifier:addressValue:xierqiTime:1405417500485 Rowkey:100003Familiy:Quilifier:ageValue:29Time:1405417500485 Rowkey:100003Familiy:Quilifier:nameValue:leonTime:1405417500485

(2)掃描指定行鍵範圍,通過末尾加0,使得結果集包含StopRow Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:itable"); Scans=newScan(); s.setStartRow(Bytes.toBytes("100001")); s.setStopRow(Bytes.toBytes("1000020")); ResultScannerrs=table.getScanner(s); for(Resultr:rs){ for(Cellcell: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();
程式碼輸出: Rowkey:100001Familiy:Quilifier:addressValue:anywhereTime:1405417403438 Rowkey:100001Familiy:Quilifier:ageValue:24Time:1405417403438 Rowkey:100001Familiy:Quilifier:nameValue:zhangtaoTime:1405417403438 Rowkey:100002Familiy:Quilifier:addressValue:shangdiTime:1405417426693 Rowkey:100002Familiy:Quilifier:ageValue:28Time:1405417426693 Rowkey:100002Familiy:Quilifier:nameValue:shichaoTime:1405417426693

(3)返回所有已經被打上刪除標記但尚未被真正刪除的資料 本測試針對rd_ns:itable表的100003行。 如果使用get結合setMaxVersions()方法能返回所有未刪除的資料,輸出如下: Rowkey:100003Familiy:Quilifier:addressValue:huilongguanTime:1405494141522 Rowkey:100003Familiy:Quilifier:addressValue:shangdiTime:1405417477465 Rowkey:100003Familiy:Quilifier:ageValue:new29Time:1405494141522 Rowkey:100003Familiy:Quilifier:nameValue:liyangTime:1405494141522

然而,使用Scan強大的s.setRaw(true)方法,可以獲得所有已經被打上刪除標記但尚未被真正刪除的資料。 程式碼如下: Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:itable"); Scans=newScan(); s.setStartRow(Bytes.toBytes("100003")); s.setRaw(true); s.setMaxVersions(); ResultScannerrs=table.getScanner(s); for(Resultr:rs){ for(Cellcell: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();

輸出結果如下: Rowkey:100003Familiy:Quilifier:addressValue:huilongguanTime:1405494141522 Rowkey:100003Familiy:Quilifier:addressValue:Time:1405417500485 Rowkey:100003Familiy:Quilifier:addressValue:xierqiTime:1405417500485 Rowkey:100003Familiy:Quilifier:addressValue:shangdiTime:1405417477465 Rowkey:100003Familiy:Quilifier:addressValue:Time:1405417448414 Rowkey:100003Familiy:Quilifier:addressValue:longzeTime:1405417448414 Rowkey:100003Familiy:Quilifier:ageValue:new29Time:1405494141522 Rowkey:100003Familiy:Quilifier:ageValue:Time:1405417500485 Rowkey:100003Familiy:Quilifier:ageValue:Time:1405417500485 Rowkey:100003Familiy:Quilifier:ageValue:29Time:1405417500485 Rowkey:100003Familiy:Quilifier:ageValue:30Time:1405417477465 Rowkey:100003Familiy:Quilifier:ageValue:31Time:1405417448414 Rowkey:100003Familiy:Quilifier:nameValue:liyangTime:1405494141522 Rowkey:100003Familiy:Quilifier:nameValue:Time:1405493879419 Rowkey:100003Familiy:Quilifier:nameValue:leonTime:1405417500485 Rowkey:100003Familiy:Quilifier:nameValue:leeTime:1405417477465 Rowkey:100003Familiy:Quilifier:nameValue:lionTime:1405417448414
(4)結合過濾器,獲取所有age在25到30之間的行 目前的資料: hbase(main):049: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.0240 seconds
程式碼: Configurationconf=HBaseConfiguration.create(); HTabletable=newHTable(conf,"rd_ns:itable");
FilterListfilterList=newFilterList(FilterList.Operator.MUST_PASS_ALL); SingleColumnValueFilterfilter1=newSingleColumnValueFilter( Bytes.toBytes("info"), Bytes.toBytes("age"), CompareOp.GREATER_OR_EQUAL, Bytes.toBytes("25") ); SingleColumnValueFilterfilter2=newSingleColumnValueFilter( Bytes.toBytes("info"), Bytes.toBytes("age"), CompareOp.LESS_OR_EQUAL, Bytes.toBytes("30") ); filterList.addFilter(filter1); filterList.addFilter(filter2); Scanscan=newScan(); scan.setFilter(filterList); ResultScannerrs=table.getScanner(scan); for(Resultr:rs){ for(Cellcell: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();

程式碼輸出: Rowkey:100002Familiy:Quilifier:addressValue:shangdiTime:1405417426693 Rowkey:100002Familiy:Quilifier:ageValue:28Time:1405417426693 Rowkey:100002Familiy:Quilifier:nameValue:shichaoTime:1405417426693 Rowkey:100003Familiy:Quilifier:addressValue:huilongguanTime:1405494141522 Rowkey:100003Familiy:Quilifier:ageValue:29Time:1405494999631 Rowkey:100003Familiy:Quilifier:nameValue:liyangTime:1405494141522
注意:
  1. HBase對列族、列名大小寫敏感
  2. 關於過濾器請參見我的另外一篇部落格:http://blog.csdn.net/u010967382/article/details/37653177