spring-hadoop之操作hbase

happyAliceYu發表於2017-03-15

Srping對於屬於java web技術的程式設計師都不會陌生,jdbcTemplate更是用的熟之又熟,下面我們來認識一下Spring大家庭的新成員:Spring-data-hadoop專案。Spring-hadoop這個專案應該是在 Spring Data 專案的一部分(Srping data其餘還包括把Spring和JDBC,REST,主流的NoSQL結合起來了)。其實再一想,Spring和Hadoop結合會發生什麼呢,其實就是把Hadoop元件的配置,任務部署之類的東西都統一到Spring的bean管理裡去了。

1.    pom.xml中引入maven依賴

<dependency>

         <groupId>org.springframework.data</groupId>

         <artifactId>spring-data-Hadoop</artifactId>

         <version>1.0.1.RELEASE</version>

</dependency>

<dependency>

         <groupId>org.apache.Hbase</groupId>

         <artifactId>hbase</artifactId>

         <version>0.94.12</version>

</dependency>

2.    Spring-hbase.xml配置檔案配置:

<?xml version="1.0" encoding="UTF-8"?> 

<beans

xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:hdp="http://www.springframework.org/schema/hadoop"

xsi:schemaLocation="

http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/hadoophttp://www.springframework.org/schema/hadoop/spring-hadoop.xsd">

 <!-- 配置zookeeper的資訊,遠端連線hbase時使用 -->  
    <hdp:configuration resources="classpath:/hbase-site.xml" />  
    <hdp:hbase-configuration configuration-ref="hadoopConfiguration" />  
    <!-- 配置HbaseTemplate -->  
    <bean id="htemplate" class="org.springframework.data.hadoop.hbase.HbaseTemplate">  
        <property name="configuration" ref="hbaseConfiguration">  
        </property>  
    <property name="encoding" value="UTF-8"></property>  
    </bean>  
 </beans> 

hbaseConfiguration其實就是指的<hdp:hbase-configuration/>配置的資訊

4、將hbase-site.xml配置檔案拷貝到src目錄下,參考內容如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <configuration>
 3   <property>
 4     <name>hbase.rootdir</name>
 5     <value>hdfs://nameservice1/hbase</value>
 6   </property>
 7   <property>
 8     <name>hbase.client.write.buffer</name>
 9     <value>62914560</value>
10   </property>
11   <property>
12     <name>hbase.client.pause</name>
13     <value>1000</value>
14   </property>
15   <property>
16     <name>hbase.client.retries.number</name>
17     <value>10</value>
18   </property>
19   <property>
20     <name>hbase.client.scanner.caching</name>
21     <value>1</value>
22   </property>
23   <property>
24     <name>hbase.client.keyvalue.maxsize</name>
25     <value>62914560</value>
26   </property>
27   <property>
28     <name>hbase.rpc.timeout</name>
29     <value>60000</value>
30   </property>
31   <property>
32     <name>hbase.security.authentication</name>
33     <value>simple</value>
34   </property>
35   <property>
36     <name>zookeeper.session.timeout</name>
37     <value>60000</value>
38   </property>
39   <property>
40     <name>zookeeper.znode.parent</name>
41     <value>/hbase</value>
42   </property>
43   <property>
44     <name>zookeeper.znode.rootserver</name>
45     <value>root-region-server</value>
46   </property>
47   <property>
48     <name>hbase.zookeeper.quorum</name>
49     <value>xinhong-hadoop-56,xinhong-hadoop-52,xinhong-hadoop-53</value>
50   </property>
51   <property>
52     <name>hbase.zookeeper.property.clientPort</name>
53     <value>2181</value>
54   </property>
55 </configuration>

5.     例項演示

public static void main(String[] args) {

       ApplicationContext context = new ClassPathXmlApplicationContext(newString[] { "spring-beans-hbase.xml" });

       BeanFactory factory = (BeanFactory) context;

       HbaseTemplate htemplate = (HbaseTemplate) factory.getBean("htemplate");

       String custom = "custom";

       htemplate.get("wcm", "10461", newRowMapper<String>(){

           @Override

           public String mapRow(Result result, int rowNum) throws Exception {

                // TODO Auto-generated methodstub

                for(KeyValue kv :result.raw()){

                    String key = newString(kv.getQualifier());

                    String value = newString(kv.getValue());

                    System.out.println(key +"= "+Bytes.toString(value.getBytes()));

                }

                return null;

           }

       });

}

檢視資料 get “wcm“, ”rowkey“ 得到一條資料

Hbase查詢總結:

HBase只提供了行級索引,因此,要進行條件查詢只有兩種方式:

(1).設計合適的行鍵(通過行鍵直接定位到資料所在的位置);

(2).通過Scan方式進行查詢,Scan可設定其實行和結束行,把這個搜尋限定在一個區域中進行;

Scan可以設定一個或多個Filter,來對行鍵、列族和列進行過濾,從而達到條件查詢的目的。

Get資料的獲取與上節Put資料插入一樣,分為多種使用方式。

1、單行獲取:get(Get get)

單行獲取每次RPC請求值傳送一個Get物件中的資料,因為Get物件初始化時需要輸入行鍵,因此可以理解為一個Get物件就代表一行。一行中可以包含多個列簇或者多個列等資訊

[html] view plain copy
  1. public void get(String tableName,String rowKey,String family,String qualifier)  
  2.     {  
  3.         Configuration conf=init();  
  4.         try {  
  5.             //進行管理員獲取  
  6.             HBaseAdmin admin=new HBaseAdmin(conf);  
  7.             if(!admin.tableExists(Bytes.toBytes(tableName)))  
  8.             {  
  9.                 System.err.println("the table "+tableName+" is not exist");  
  10.                 admin.close();  
  11.                 System.exit(1);  
  12.             }  
  13.             admin.close();  
  14.             //建立表連線  
  15.             HTable table=new HTable(conf,TableName.valueOf(tableName));  
  16.             //建立一個獲取物件  
  17.             Get get=new Get(Bytes.toBytes(rowKey));  
  18.             //根據傳入的值,進行獲取判斷  
  19.             if(family!=null && qualifier!=null)  
  20.             {  
  21.                 get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));  
  22.             }  
  23.             else if(family != null && qualifier == null)  
  24.             {  
  25.                 get.addFamily(Bytes.toBytes(family));  
  26.             }  
  27.             //獲取資料  
  28.             Result result=table.get(get);  
  29.             KeyValue[] kvs=result.raw();  
  30.             for(KeyValue kv:kvs)  
  31.             {  
  32.                 System.out.println(Bytes.toString(kv.getRow()));  
  33.                 System.out.println(Bytes.toString(kv.getFamily()));  
  34.                 System.out.println(Bytes.toString(kv.getQualifier()));  
  35.                 System.out.println(Bytes.toString(kv.getValue()));  
  36.             }  
  37.         } catch (Exception e) {  
  38.             // TODO: handle exception  
  39.             e.printStackTrace();  
  40.         }  
  41.     }  

從上述程式碼中我們可以看到,Get例項使用 addColumn / addFamily 著兩個函式想Get中新增搜尋範圍。如果沒有新增,則表示將整行資料進行返回。如果新增列簇,則將指定的列簇中的所有列進行返回,如果指定列,則將制定的列進行返回。

2、獲取多行: get(List<Get> list)

多行獲取獲取實質就是在程式碼中對List<Get>例項進行迭代,從而傳送多次資料請求(即多個RPC請求與資料操作,一次請求包含一次RPC請求和一次資料傳輸)。

[java] view plain copy
  1. public void getList(String tableName,String[] rows,String[] families,String[] qualifiers)  
  2.     {  
  3.         Configuration conf=init();  
  4.         try {  
  5.             //判斷表是否存在  
  6.             HBaseAdmin admin=new HBaseAdmin(conf);  
  7.             if(!admin.tableExists(Bytes.toBytes(tableName)))  
  8.             {  
  9.                 System.err.println("the table "+tableName+" is not exist");  
  10.                 admin.close();  
  11.                 System.exit(1);  
  12.             }  
  13.             //建立表連線  
  14.             HTable table=new HTable(conf, Bytes.toBytes(tableName));  
  15.             List<Get> gets=new ArrayList<>();  
  16.             int length=rows.length;  
  17.             for(int i=0;i<length;i++)  
  18.             {  
  19.                 Get get=new Get(Bytes.toBytes(rows[i]));  
  20.                 get.addColumn(Bytes.toBytes(families[i]), Bytes.toBytes(qualifiers[i]));  
  21.                 gets.add(get);  
  22.             }  
  23.             //對結果進行遞迴輸出  
  24.             Result[] results=table.get(gets);  
  25.             for(Result result:results)  
  26.             {  
  27.                 KeyValue[] keyValues=result.raw();  
  28.                 for(KeyValue kv:keyValues)  
  29.                 {  
  30.                     System.out.println(Bytes.toString(kv.getRow()));  
  31.                     System.out.println(Bytes.toString(kv.getFamily()));  
  32.                     System.out.println(Bytes.toString(kv.getQualifier()));  
  33.                     System.out.println(Bytes.toString(kv.getValue()));  
  34.                 }  
  35.             }  
  36.         } catch (Exception e) {  
  37.             // TODO: handle exception  
  38.             e.printStackTrace();  
  39.         }  
  40.     }  

3、獲取資料或者前一行:getRowOrBefore()

該函式是HTable類提供的一個藉口。作為為:當引數中的行存在時,則將本行指定的列簇進行返回,如果不存在時,則返回表中存在的指定行的前一行的資料進行返回。

[java] view plain copy
  1. public void getRowOrBefore(String tableName,String row,String family,String qualifier)  
  2.     {  
  3.         Configuration conf=init();  
  4.         try {  
  5.             HBaseAdmin admin=new HBaseAdmin(conf);  
  6.             if(!admin.tableExists(tableName))  
  7.             {  
  8.                 System.out.println("the table "+tableName+" is not exist");  
  9.                 admin.close();  
  10.                 System.exit(1);  
  11.             }  
  12.             //建立表連線  
  13.             HTable table=new HTable(conf, tableName);  
  14.             //執行函式  
  15.             Result result=table.getRowOrBefore(Bytes.toBytes(row),Bytes.toBytes(family));  
  16.             //進行迴圈  
  17.             KeyValue[] keyValues=result.raw();  
  18.             for(KeyValue kv: keyValues)  
  19.             {  
  20.                 System.out.println(Bytes.toString(kv.getRow()));  
  21.                 System.out.println(Bytes.toString(kv.getFamily()));  
  22.                 System.out.println(Bytes.toString(kv.getQualifier()));  
  23.                 System.out.println(Bytes.toString(kv.getValue()));  
  24.                 System.out.println(Bytes.toString(kv.getKey()));  
  25.             }  
  26.             table.close();  
  27.         } catch (Exception e) {  
  28.             // TODO: handle exception  
  29.         }  
  30.     }  

注意:在函式中需要注意的是,所有行的row在HBase中的儲存都是byte陣列,其沒有具體的型別,因此row-10 是小於 row-9。因此在進行比較是在第五位中1是小於9,HBase資料庫則會認為row-10 是小於 row-9 的。如果指定順序的話,則需要將資料的row的位數規定一致。則 row-9 應該更改為 row-09。通過這樣的修改可以保證 row-09 是小於 row-10的。

4、結果顯示:Result物件、KeyValue物件與Cell物件

(1)Result物件,在查詢得到的結果,每一行資料會被作為一個Result物件,將資料存入到一個Result例項中。當我們需要獲取一行資料時則需要獲取該行資料所在的Result物件即可。該物件內部封裝了一個KeyValue 物件陣列。在0.98.4以前的本班。result類提供了 raw() 方法去獲取整個result物件中的KeyValue陣列。在0.98.4以後,則提供了一個新的節後: rowCells() 方法獲取KeyValue物件,不過返回的是KeyValue 物件父類引用。

(2)KeyValue物件。該物件我們已經進行過介紹。因此這裡我們只進行其使用的展示

[java] view plain copy
  1. public void KVObject(String tableName,String row,String family,String qualifier)  
  2.     {  
  3.         Configuration conf=init();  
  4.         try {  
  5.             HBaseAdmin admin=new HBaseAdmin(conf);  
  6.             if(!admin.tableExists(Bytes.toBytes(tableName)))  
  7.             {  
  8.                 System.err.println("the table "+tableName+" is not exist");  
  9.                 admin.close();  
  10.                 System.exit(1);  
  11.             }  
  12.             admin.close();  
  13.             //建立表連線  
  14.             HTable table=new HTable(conf, tableName);  
  15.             //查詢一行並返回result物件  
  16.             Get get=new Get(Bytes.toBytes(row));  
  17.             Result result=table.get(get);  
  18.             //進行迴圈  
  19.             KeyValue[] keyValues=result.raw();  
  20.             for(KeyValue kv: keyValues)  
  21.             {  
  22.                 System.out.println(Bytes.toString(kv.getRow()));  
  23.                 System.out.println(Bytes.toString(kv.getFamily()));  
  24.                 System.out.println(Bytes.toString(kv.getQualifier()));  
  25.                 System.out.println(Bytes.toString(kv.getValue()));  
  26.                 System.out.println(Bytes.toString(kv.getKey()));  
  27.             }  
  28.             table.close();  
  29.         } catch (Exception e) {  
  30.             // TODO: handle exception  
  31.             e.printStackTrace();  
  32.         }  
  33.     }  

(3)Cell物件:Cell物件是KeyValue物件的父類,Cell物件中的所有方法在KeyValue物件中全部被實現。因此根據繼承的特徵,我們可以使用Cell物件中的API操作KeyValue物件。

[java] view plain copy
  1. public void CellObject(String tableName,String row,String family,String qualifier)  
  2.     {  
  3.         Configuration conf=init();  
  4.         try {  
  5.             //檢視錶是否存在  
  6.             HBaseAdmin admin=new HBaseAdmin(conf);  
  7.             if(!admin.tableExists(tableName))  
  8.             {  
  9.                 System.out.println("the table "+tableName+" is not exist");  
  10.                 admin.close();  
  11.                 System.exit(1);  
  12.             }  
  13.             admin.close();  
  14.             //建立表連線  
  15.             HTable table=new HTable(conf, tableName);  
  16.             Get get=new Get(Bytes.toBytes(row));  
  17.             get.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));  
  18.             Result result=table.get(get);  
  19.             Cell[] cells=result.rawCells();  
  20.             for(Cell cell:cells)  
  21.             {  
  22.                 System.out.println(Bytes.toString(cell.getRow()));  
  23.                 System.out.println(Bytes.toString(cell.getFamily()));  
  24.                 System.out.println(Bytes.toString(cell.getQualifier()));  
  25.                 System.out.println(Bytes.toString(cell.getValue()));  
  26.             }  
  27.             table.close();  
  28.         } catch (Exception e) {  
  29.             // TODO: handle exception  
  30.         }  
  31.     }  






查詢列族下的列的資料:

1 public List<String> find(String tableName,String family,String cloumn){
2         List<String> rows = hbaseTemplate.find(tableName, family,cloumn, new RowMapper<String>() {
3             public String mapRow(Result result, int rowNum) throws Exception {
4                 return Bytes.toString(result.getRow());
5             }
6         });
7         return rows;
8     }

查詢指定行健的一列資料:

1 public String get(String tableName,String family,String cloumn,String rowKey){
2         String context = hbaseTemplate.get(tableName, "NCEP_p_wa_2014032212_tp_006.nc", family, cloumn, new RowMapper<String>() {
3             public String mapRow(Result result, int rowNum) throws Exception {
4                 return Bytes.toString(result.value());
5               }
6             });
7         return context;
8     }

5.    基本命令

檢視有哪些表list

檢視所有資料 scan “表名”

檢視資料 get “wcm“,”lrowkey“ 得到一條資料

 刪除一條資料delete “表名”,”主鍵”,”列族”,”列”

 刪除整條資料deleteAll “表名”,”主鍵”

Hbase的特點:

>>在命令視窗只能一次更新一個單元格;

>>在程式中通過呼叫HTable.setAutoFlush(false)方法可以將HTable寫客戶端的自動flush關閉,這樣可以批量寫入資料到 HBase,而不是有一條put就執行一次更新,只有當put填滿客戶端寫快取時,才實際向HBase服務端發起寫請求。預設情況下auto flush是開啟的。

相關文章