JAVA操作HBASE數據操作詳解

Hbase對於建表,和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.創建表

廢話不多說,直接上樣板代碼,代碼後再說明注意事項和知識點:

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HBaseAdmin admin =  new  HBaseAdmin(conf);  
  3.          //create  namespace  named "my_ns"  
  4.         admin.createNamespace(NamespaceDescriptor. create ( "my_ns" ).build());  
  5. <span style="white-space:pre">  </span>//create tableDesc, with  namespace  name "my_ns" and table name "mytable "  
  6.         HTableDescriptor tableDesc =  new  HTableDescriptor(TableName. valueOf ("my_ns:mytable" ));  
  7.          tableDesc.setDurability(Durability. SYNC_WAL );  
  8.          //add a column family " mycf "  
  9.         HColumnDescriptor hcd =  new  HColumnDescriptor( "mycf" );  
  10.         tableDesc.addFamily(hcd);  
  11.         admin.createTable(tableDesc);  
  12.         admin.close();  


關鍵知識點:

  1. 必須將HBase集羣的hbase-site.xml文件添加進工程的classpath中,否則Configuration conf = HBaseConfiguration. create () 代碼獲取不到需要的集羣相關信息,也就無法找到集羣,運行程序時會報錯; 
  2. HTableDescriptor tableDesc =  new  HTableDescriptor(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.刪除表

刪除表沒創建表那麼多學問,直接上代碼:

      

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.       HBaseAdmin admin =  new  HBaseAdmin(conf);  
  3.       String tablename =  "my_ns:mytable" ;  
  4.        if (admin.tableExists(tablename)) {  
  5.            try  {  
  6.               admin.disableTable(tablename);  
  7.               admin.deleteTable(tablename);  
  8.           }  catch  (Exception e) {  
  9.                //  TODO : handle exception  
  10.               e.printStackTrace();  
  11.           }  
  12.       }  
  13.       admin.close();  

一般很少用到刪除表。

說明 :刪除表前必須先disable表。


4.修改表

4.1.實例代碼

(1)刪除列族、新增列族

修改之前,四個列族:

[plain] view plain copy
  1. hbase(main):014:0> describe 'rd_ns:itable'  
  2. DESCRIPTION                                                                                                        ENABLED  
  3. 'rd_ns:itable', {NAME => ' info ', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', V true  
  4. ERSIONS => '10', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false',  
  5. BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => ' newcf ', DATA_BLOCK_ENCODING => 'NONE  
  6. ', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647',  
  7. MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'tr  
  8. ue'}, {NAME => ' note ', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS =>  
  9. '10', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE  
  10. => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => ' sysinfo', DATA_BLOCK_ENCODING => 'NONE', BLOOM  
  11. FILTER => 'ROW', REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647', MIN_VERS  
  12. IONS => '0', KEEP_DELETED_CELLS => 'true', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}  
  13. 1 row(s) in 0.0450 seconds  

修改表,刪除三個列族,新增一個列族,代碼如下

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HBaseAdmin admin =  new  HBaseAdmin(conf);  
  3.         String tablename =  "rd_ns:itable" ;  
  4.          if (admin.tableExists(tablename)) {  
  5.              try  {  
  6.                 admin.disableTable(tablename);  
  7.                  //get the TableDescriptor of target table  
  8.                 HTableDescriptor newtd =  admin.getTableDescriptor (Bytes. toBytes ("rd_ns:itable" ));                  
  9.                  //remove 3 useless column families  
  10.                 newtd.removeFamily(Bytes. toBytes ( "note" ));  
  11.                 newtd.removeFamily(Bytes. toBytes ( "newcf" ));  
  12.                 newtd.removeFamily(Bytes. toBytes ( "sysinfo" ));                 
  13.                 //create HColumnDescriptor for new column family  
  14.                 HColumnDescriptor newhcd =  new  HColumnDescriptor( "action_log" );  
  15.                 newhcd.setMaxVersions(10);  
  16.                 newhcd.setKeepDeletedCells( true );                  
  17.                  //add the new column family(HColumnDescriptor) to HTableDescriptor  
  18.                 newtd.addFamily(newhcd);                  
  19.                  //modify target table  struture  
  20.                 admin. modifyTable (Bytes. toBytes ( "rd_ns:itable" ),newtd);                
  21.                 admin.enableTable(tablename);  
  22.             }  catch  (Exception e) {  
  23.                  //  TODO : handle exception  
  24.                 e.printStackTrace();  
  25.             }  
  26.         }  
  27.         admin.close();  

  

修改之後:

[plain] view plain copy
  1. hbase(main):015:0> describe 'rd_ns:itable'  
  2. DESCRIPTION                                                                                                        ENABLED  
  3. 'rd_ns:itable', {NAME => ' action_log ', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE =>  true  
  4. '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647', MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'tr  
  5. ue', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => ' info ', DATA_BLOCK_ENCODING => '  
  6. NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '10', COMPRESSION => 'NONE', MIN_VERSIONS => '  
  7. 0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE =>  
  8. 'true'}  
  9. 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)

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.       HBaseAdmin admin =  new  HBaseAdmin(conf);  
  3.       String tablename =  "rd_ns:itable" ;  
  4.        if (admin.tableExists(tablename)) {  
  5.            try  {  
  6.               admin.disableTable(tablename);  
  7.                //get the TableDescriptor of target table  
  8.               HTableDescriptor htd = admin.getTableDescriptor(Bytes. toBytes ("rd_ns:itable" ));  
  9.               HColumnDescriptor infocf = htd.getFamily(Bytes. toBytes ( "info" ));  
  10.               infocf.setMaxVersions(100);  
  11.                //modify target table  struture  
  12.               admin.modifyTable(Bytes. toBytes ( "rd_ns:itable" ),htd);  
  13.               admin.enableTable(tablename);  
  14.           }  catch  (Exception e) {  
  15.                //  TODO : handle exception  
  16.               e.printStackTrace();  
  17.           }  
  18.       }  
  19.       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)插入行

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.        HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.        Put put =  new  Put(Bytes. toBytes ( "100001" ));  
  4.        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ), Bytes. toBytes ("lion" ));  
  5.        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ), Bytes. toBytes ("shangdi" ));  
  6.        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "age" ), Bytes. toBytes ("30" ));  
  7.        put.setDurability(Durability. SYNC_WAL );  
  8.        table.put(put);  
  9.        table.close();  

(2)更新行   

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.       HTable table =  new  HTable(conf,  "rd_ns:leetable" );          
  3.       Put put =  new  Put(Bytes. toBytes ( "100001" ));  
  4. put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ), Bytes. toBytes ("lee" ));  
  5.       put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ), Bytes. toBytes ("longze" ));  
  6.       put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "age" ), Bytes. toBytes ("31" ));  
  7.       put.setDurability(Durability. SYNC_WAL );   
  8.       table.put(put);           
  9.       table.close();  


  

注意:
  1. Put的構造函數都需要指定行鍵,如果是全新的行鍵,則新增一行;如果是已有的行鍵,則更新現有行。

  2. 創建Put對象及put.add過程都是在構建一行的數據,創建Put對象時相當於創建了行對象,add的過程就是往目標行裏添加cell,直到table.put纔將數據插入表格;
  3. 以上代碼創建Put對象用的是構造函數1,也可用構造函數2,第二個參數是時間戳; 
  4. Put還有別的構造函數,請查閱官網API。

(3) 從目標字符串中提取子串,作爲行鍵,構建Put       

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.        HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.        Put put =  new  Put(Bytes. toBytes ( "100001_100002" ),7,6);  
  4.        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ), Bytes. toBytes ("show" ));  
  5.        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ), Bytes. toBytes ("caofang" ));  
  6.        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "age" ), Bytes. toBytes ("30" ));        
  7.        table.put(put);  
  8.        table.close();  

注意,關於: Put put =  new  Put(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   deleteColumn s (byte[] family, byte[] qualifier)     刪除指定列的 所有版本的數據。
  • Delete   deleteColumn (byte[] family, byte[] qualifier, long  timestamp )     刪除指定列的 指定版本 的數據。
  • Delete   deleteColumn s (byte[] family, byte[] qualifier, long  timestamp )     刪除指定列的,時間戳 小於等於給定時間戳 的 所有 版本的數據。
  • Delete   deleteFamily (byte[] family)     刪除指定列族的所有列的 所有 版本數據。
  • Delete   deleteFamily (byte[] family, long timestamp)     刪除指定列族的所有列中時間戳 小於等於 指定時間戳 的所有數據。
  • Delete   deleteFamilyVersion (byte[] family, long timestamp)     刪除指定列族中所有 列的時間戳 等於 指定時間戳 的版本數據。
  • void setTimestamp (long timestamp)     爲Delete對象設置時間戳。

6.3.實例代碼

(1)刪除整行的所有列族、所有行、所有版本       

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HTable table =  new  HTable(conf,  "rd_ns:leetable" );         
  3.         Delete delete =  new  Delete(Bytes. toBytes ( "000" ));  
  4.         table.delete(delete);  
  5.         table.close();  

(2)刪除 指定列的最新版本

以下是刪除之前的數據,注意看100003行的info:address,這是該列最新版本的數據,值是caofang1,在這之前的版本值是caofang:

[sql] view plain copy
  1. hbase(main):007:0> scan 'rd_ns:leetable'  
  2. ROW                       COLUMN+CELL  
  3. 100001                   column=info:address, timestamp=1405304843114, value=longze  
  4. 100001                   column=info:age, timestamp=1405304843114, value=31  
  5. 100001                   column=info:nametimestamp=1405304843114, value=leon  
  6. 100002                   column=info:address, timestamp=1405305471343, value=caofang  
  7. 100002                   column=info:age, timestamp=1405305471343, value=30  
  8. 100002                   column=info:nametimestamp=1405305471343, value=show  
  9. 100003                   column=info:address, timestamp=1405390959464, value=caofang1  
  10. 100003                   column=info:age, timestamp=1405390959464, value=301  
  11. 100003                   column=info:nametimestamp=1405390959464, value=show1  
  12. 3 row(s) in 0.0270 seconds  

執行以下代碼:

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.         Delete delete =  new  Delete(Bytes. toBytes ( "100003" ));  
  4.         delete.deleteColumn(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ));      
  5.         table.delete(delete);  
  6.         table.close();   

然後查看數據,發現100003列的info:address列的值顯示爲前一個版本的caofang了!其餘值均不變:

[plain] view plain copy
  1. hbase(main):008:0> scan 'rd_ns:leetable'  
  2. ROW                       COLUMN+CELL  
  3. 100001                   column=info:address, timestamp=1405304843114, value=longze  
  4. 100001                   column=info:age, timestamp=1405304843114, value=31  
  5. 100001                   column=info:name, timestamp=1405304843114, value=leon  
  6. 100002                   column=info:address, timestamp=1405305471343, value=caofang  
  7. 100002                   column=info:age, timestamp=1405305471343, value=30  
  8. 100002                   column=info:name, timestamp=1405305471343, value=show  
  9. 100003                   column=info:address, timestamp=1405390728175, value=caofang  
  10. 100003                   column=info:age, timestamp=1405390959464, value=301  
  11. 100003                   column=info:name, timestamp=1405390959464, value=show1  
  12. 3 row(s) in 0.0560 seconds  

(3)刪除 指定列的所有版本

接以上場景,執行以下代碼:

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.        Delete delete =  new  Delete(Bytes. toBytes ( "100003" ));  
  4.         delete. deleteColumns (Bytes. toBytes ( "info" ), Bytes. toBytes ( "address"));        
  5.         table.delete(delete);  
  6.         table.close();  

然後我們會發現,100003行的整個info:address列都沒了:

[plain] view plain copy
  1. hbase(main):009:0> scan 'rd_ns:leetable'  
  2. ROW                       COLUMN+CELL  
  3. 100001                   column=info:address, timestamp=1405304843114, value=longze  
  4. 100001                   column=info:age, timestamp=1405304843114, value=31  
  5. 100001                   column=info:name, timestamp=1405304843114, value=leon  
  6. 100002                   column=info:address, timestamp=1405305471343, value=caofang  
  7. 100002                   column=info:age, timestamp=1405305471343, value=30  
  8. 100002                   column=info:name, timestamp=1405305471343, value=show  
  9. 100003                   column=info:age, timestamp=1405390959464, value=301  
  10. 100003                   column=info:name, timestamp=1405390959464, value=show1  
  11. 3 row(s) in 0.0240 seconds  

(4) 刪除指定列族中所有 列的時間戳 等於 指定時間戳 的版本數據

爲了演示效果,我已經向100003行的info:address列新插入一條數據

[plain] view plain copy
  1. hbase(main):010:0> scan 'rd_ns:leetable'  
  2. ROW                       COLUMN+CELL  
  3. 100001                   column=info:address, timestamp=1405304843114, value=longze  
  4. 100001                   column=info:age, timestamp=1405304843114, value=31  
  5. 100001                   column=info:name, timestamp=1405304843114, value=leon  
  6. 100002                   column=info:address, timestamp=1405305471343, value=caofang  
  7. 100002                   column=info:age, timestamp=1405305471343, value=30  
  8. 100002                   column=info:name, timestamp=1405305471343, value=show  
  9. 100003                   column=info:address, timestamp= 1405391883886 , value=shangdi  
  10. 100003                   column=info:age, timestamp= 1405390959464 , value=301  
  11. 100003                   column=info:name, timestamp= 1405390959464 , value=show1  
  12. 3 row(s) in 0.0250 seconds  

現在,我們的目的是刪除info列族中,時間戳爲1405390959464的所有列數據

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.        HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.        Delete delete =  new  Delete(Bytes. toBytes ( "100003" ));  
  4.        delete. deleteFamilyVersion (Bytes. toBytes ( "info" ), 1405390959464L);  
  5.        table.delete(delete);  
  6.        table.close();  


[plain] view plain copy
  1. hbase(main):011:0> scan 'rd_ns:leetable'  
  2. ROW                       COLUMN+CELL  
  3. 100001                   column=info:address, timestamp=1405304843114, value=longze  
  4. 100001                   column=info:age, timestamp=1405304843114, value=31  
  5. 100001                   column=info:name, timestamp=1405304843114, value=leon  
  6. 100002                   column=info:address, timestamp=1405305471343, value=caofang  
  7. 100002                   column=info:age, timestamp=1405305471343, value=30  
  8. 100002                   column=info:name, timestamp=1405305471343, value=show  
  9. 100003                   column=info:address, timestamp= 1405391883886 , value=shangdi  
  10. 100003                   column=info:age, timestamp= 1405390728175 , value=30  
  11. 100003                   column=info:name, timestamp= 1405390728175 , value=show  
  12. 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.常用方法

  • Get addFamily(byte[] family)  指定希望獲取的列族 
  • Get addColumn(byte[] family, byte[] qualifier)  指定希望獲取的列 
  • Get setTimeRange(long minStamp, long maxStamp)  設置獲取數據的 時間戳範圍
  • Get setTimeStamp(long timestamp)  設置獲取數據的時間戳 
  • Get setMaxVersions(int maxVersions) 設定獲取數據的版本數 
  • Get setMaxVersions()  設定獲取數據的 所有版本 
  • Get setFilter(Filter filter)  爲Get對象添加過濾器,過濾器詳解請參見:http://blog.csdn.net/lr131425/article/details/72676254
  • void setCacheBlocks(boolean cacheBlocks)  設置該Get獲取的數據是否緩存在內存中 

7.3.實測代碼

(1)獲取行鍵指定行的 所有列族、所有列 的 最新版本 數據  

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.        HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.        Get get =  new  Get(Bytes. toBytes ( "100003" ));  
  4.        Result r = table.get(get);  
  5.         for  (Cell cell : r.rawCells()) {  
  6.            System. out .println(  
  7.                     "Rowkey : " +Bytes. toString (r.getRow())+  
  8.                     "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+  
  9.                     "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))  
  10.                    );  
  11.        }  
  12.        table.close();  


代碼輸出:

Rowkey : 100003   Familiy:Quilifier : address   Value : qinghe

Rowkey : 100003   Familiy:Quilifier : age   Value : 28

Rowkey : 100003   Familiy:Quilifier : name   Value : shichao

  

(2)獲取行鍵指定行中, 指定列 的最新版本數據

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.        HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.        Get get =  new  Get(Bytes. toBytes ( "100003" ));  
  4.         get.addColumn(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ));  
  5.        Result r = table.get(get);  
  6.         for  (Cell cell : r.rawCells()) {  
  7.            System. out .println(  
  8.                     "Rowkey : " +Bytes. toString (r.getRow())+  
  9.                     "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+  
  10.                     "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))  
  11.                    );  
  12.        }  
  13.        table.close();  

代碼輸出:

Rowkey : 100003   Familiy:Quilifier : name   Value : shichao

  

(3)獲取行鍵指定的行中, 指定時間戳 的數據

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HTable table =  new  HTable(conf,  "rd_ns:leetable" );  
  3.         Get get =  new  Get(Bytes. toBytes ( "100003" ));  
  4.          get.setTimeStamp(1405407854374L);  
  5.         Result r = table.get(get);  
  6.          for  (Cell cell : r.rawCells()) {  
  7.             System. out .println(  
  8.                      "Rowkey : " +Bytes. toString (r.getRow())+  
  9.                      "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+  
  10.                      "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))  
  11.                     );  
  12.         }  
  13.         table.close();   

代碼輸出了上面scan命令輸出中沒有展示的歷史數據:

Rowkey : 100003   Familiy:Quilifier : address   Value : huangzhuang

Rowkey : 100003   Familiy:Quilifier : age   Value : 32

Rowkey : 100003   Familiy:Quilifier : name   Value : lily

  

(4)獲取行鍵指定的行中, 所有版本 的數據

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.     HTable table =  new  HTable(conf,  "rd_ns:itable" );  
  3.     Get get =  new  Get(Bytes. toBytes ( "100003" ));  
  4.     get.setMaxVersions();  
  5.     Result r = table.get(get);  
  6.      for  (Cell cell : r.rawCells()) {  
  7.         System. out .println(  
  8.                  "Rowkey : " +Bytes. toString (r.getRow())+  
  9.                  "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+  
  10.                  "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+  
  11.                  "   Time : " +cell.getTimestamp()  
  12.                 );  
  13.     }  
  14.     table.close();      

代碼輸出:

Rowkey : 100003   Familiy:Quilifier : address   Value : xierqi   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : address   Value : shangdi   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : address   Value : longze   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 30   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : age   Value : 31   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : name   Value : leon   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : name   Value : lee   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : name   Value : lion   Time : 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"打頭的行:

[java] view plain copy
  1. HTable htable = ...      // instantiate HTable  
  2. Scan scan = new Scan();  
  3. scan.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("attr"));  
  4. scan.setStartRow( Bytes.toBytes("row"));                   // start key is inclusive  
  5. scan.setStopRow( Bytes.toBytes("row" +  (char)0));  // stop key is exclusive  
  6. ResultScanner rs = htable.getScanner(scan);  
  7. try {  
  8. for (Result r = rs.next(); r != null; r = rs.next()) {  
  9. // process result...  
  10. finally {  
  11. rs.close(); // always close the ResultScanner!  
  12. }  

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)   設定緩存在內存中的行數,緩存得越多,以後查詢結果越快,同時也消耗更多內存
  • void setRaw (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 on column families  that have KEEP_DELETED_ROWS enabled. It is an error to specify any column when "raw" is set.

hcd.setKeepDeletedCells(true);

8.3.實測代碼

(1)掃描表中的 所有行 的最新版本數據

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.    HTable table =  new  HTable(conf,  "rd_ns:itable" );  
  3.    Scan s =  new  Scan();  
  4.    ResultScanner rs = table.getScanner(s);  
  5.     for  (Result r : rs) {  
  6.         for  (Cell cell : r.rawCells()) {  
  7.            System. out .println(  
  8.                     "Rowkey : " +Bytes. toString (r.getRow())+  
  9.                     "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier(cell))+  
  10.                     "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+  
  11.                     "   Time : " +cell.getTimestamp()  
  12.                    );  
  13.        }  
  14.    }  
  15.    table.close();  

代碼輸出:

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 : 100002   Familiy:Quilifier : address   Value : shangdi   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : age   Value : 28   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : name   Value : shichao   Time : 1405417426693

Rowkey : 100003   Familiy:Quilifier : address   Value : xierqi   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : name   Value : leon   Time : 1405417500485

  

(2) 掃描指定行鍵範圍,通過末尾加0,使得結果集包含StopRow    

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.       HTable table =  new  HTable(conf,  "rd_ns:itable" );  
  3.       Scan s =  new  Scan();  
  4.       s. setStartRow (Bytes. toBytes ( "100001" ));  
  5.       s. setStopRow (Bytes. toBytes ( " 1000020 " ));  
  6.       ResultScanner rs = table.getScanner(s);  
  7.        for  (Result r : rs) {  
  8.            for  (Cell cell : r.rawCells()) {  
  9.               System. out .println(  
  10.                        "Rowkey : " +Bytes. toString (r.getRow())+  
  11.                        "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier(cell))+  
  12.                        "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+  
  13.                        "   Time : " +cell.getTimestamp()  
  14.                       );  
  15.           }  
  16.       }  
  17.       table.close();  

代碼輸出:

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 : 100002   Familiy:Quilifier : address   Value : shangdi   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : age   Value : 28   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : name   Value : shichao   Time : 1405417426693   

(3) 返回 所有已經被打上刪除標記但尚未被真正刪除 的數據

測試針對rd_ns:itable表的100003行。

如果使用get結合 setMaxVersions() 方法能返回所有未刪除的數據,輸出如下:

Rowkey : 100003   Familiy:Quilifier : address   Value : huilongguan   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : address   Value : shangdi   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : age   Value : new29   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : name   Value : liyang   Time : 1405494141522

  

然而,使用Scan強大的 s.setRaw( true ) 方法,可以獲得所有 已經被打上刪除標記但尚未被真正刪除 的數據。

代碼如下:     

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HTable table =  new  HTable(conf,  "rd_ns:itable" );  
  3.         Scan s =  new  Scan();  
  4.         s.setStartRow(Bytes. toBytes ( "100003" ));  
  5.         s.setRaw( true );  
  6.         s.setMaxVersions();  
  7.         ResultScanner rs = table.getScanner(s);  
  8.          for  (Result r : rs) {  
  9.              for  (Cell cell : r.rawCells()) {  
  10.                 System. out .println(  
  11.                          "Rowkey : " +Bytes. toString (r.getRow())+  
  12.                          "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier(cell))+  
  13.                          "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+  
  14.                          "   Time : " +cell.getTimestamp()  
  15.                         );  
  16.             }  
  17.         }  
  18.         table.close();  


輸出結果如下:

Rowkey : 100003   Familiy:Quilifier : address   Value : huilongguan   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : address   Value :    Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : address   Value : xierqi   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : address   Value : shangdi   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : address   Value :    Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : address   Value : longze   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : age   Value : new29   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : age   Value :    Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value :    Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 30   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : age   Value : 31   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : name   Value : liyang   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : name   Value :    Time : 1405493879419

Rowkey : 100003   Familiy:Quilifier : name   Value : leon   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : name   Value : lee   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : name   Value : lion   Time : 1405417448414

(4) 結合過濾器,獲取所有age在25到30之間的行

目前的數據:

[plain] view plain copy
  1. hbase(main):049:0> scan 'rd_ns:itable'  
  2. ROW                                           COLUMN+CELL  
  3. 100001                                       column=info:address, timestamp=1405417403438, value=anywhere  
  4. 100001                                       column=info:age, timestamp=1405417403438, value=24  
  5. 100001                                       column=info:name, timestamp=1405417403438, value=zhangtao  
  6. 100002                                       column=info:address, timestamp=1405417426693, value=shangdi  
  7. 100002                                       column=info:age, timestamp=1405417426693, value=28  
  8. 100002                                       column=info:name, timestamp=1405417426693, value=shichao  
  9. 100003                                       column=info:address, timestamp=1405494141522, value=huilongguan  
  10. 100003                                       column=info:age, timestamp=1405494999631, value=29  
  11. 100003                                       column=info:name, timestamp=1405494141522, value=liyang  
  12. 3 row(s) in 0.0240 seconds  

代碼:

[java] view plain copy
  1. Configuration conf = HBaseConfiguration. create ();  
  2.         HTable table =  new  HTable(conf,  "rd_ns:itable" );  
  3.         FilterList filterList =  new  FilterList(FilterList.Operator. MUST_PASS_ALL );    
  4.         SingleColumnValueFilter filter1 =  new  SingleColumnValueFilter(  
  5.                 Bytes. toBytes ( "info" ),  
  6.                 Bytes. toBytes ( "age" ),  
  7.                 CompareOp. GREATER_OR_EQUAL ,  
  8.                 Bytes. toBytes ( "25" )  
  9.                 );  
  10.         SingleColumnValueFilter filter2 =  new  SingleColumnValueFilter(  
  11.                 Bytes. toBytes ( "info" ),  
  12.                 Bytes. toBytes ( "age" ),  
  13.                 CompareOp. LESS_OR_EQUAL ,  
  14.                 Bytes. toBytes ( "30" )  
  15.                 );  
  16.         filterList.addFilter(filter1);  
  17.         filterList.addFilter(filter2);  
  18.         Scan scan =  new  Scan();  
  19.         scan.setFilter(filterList);  
  20.         ResultScanner rs = table.getScanner(scan);  
  21.          for  (Result r : rs) {  
  22.              for  (Cell cell : r.rawCells()) {  
  23.                 System. out .println(  
  24.                          "Rowkey : " +Bytes. toString (r.getRow())+  
  25.                          "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier(cell))+  
  26.                          "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+  
  27.                          "   Time : " +cell.getTimestamp()  
  28.                         );  
  29.             }  
  30.         }  
  31.         table.close();  

    

  

代碼輸出:

Rowkey : 100002   Familiy:Quilifier : address   Value : shangdi   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : age   Value :  28    Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : name   Value : shichao   Time : 1405417426693

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


發佈了6 篇原創文章 · 獲贊 40 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章