HiveHbase集成實踐


作者:Syn良子 出處:http://www.cnblogs.com/cssdongl/p/6857891.html 轉載請注明出處

簡單的說就是可以通過Hive SQL直接對hbase的表進行讀寫操作,對了,這里可能有人會問,為啥要這么集成呢,有什么場景呢。那我舉個場景栗子,比如我們可能會用Hbase做后台歷史日志的存儲和統計.

而進行離線日志的存儲統計的時候,你當然可以選擇用Hadoop MR或者Spark來進行統計和分析並存入相應的Hbase表結構,隨后前台可以利用thrift等方式進行實時的查詢,ok,這些都能滿足需求.

那么時間長了以后,隨着項目需求和數據種類以及臨時需求的增多,寫MR和Spark會不會很累?所以,當然想到可不可以直接通過Hive SQL來直接讀寫hbase,這就是一個很普通的需求.

廢話不說,官網有現成的例子可以參考,很詳細:https://cwiki.apache.org/confluence/display/Hive/HBaseIntegration

我整理和總結一下一些細節和遇到的問題

1.數據准備

在hive中創建個基礎表並插入數據,注意下面紅色路徑的txt可以在hive的examples目錄下找到

CREATE TABLE pokes (foo INT, bar STRING);
LOAD DATA LOCAL INPATH '/data/examples/files/kv1.txt' OVERWRITE INTO TABLE pokes;

2.Hive中創建Hbase表

這種情況就是在hive和hbase中同時創建新表然后建立hive和hbase的表映射關系,如果刪除hive中的表,那么hbase的表也會消失,如下

CREATE TABLE hbase_table_1(key int, value string) 
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = ":key,cf1:val")
TBLPROPERTIES ("hbase.table.name" = "xyz", "hbase.mapred.output.outputtable" = "xyz");
INSERT OVERWRITE TABLE hbase_table_1 SELECT * FROM pokes WHERE foo=98;
這里解釋下,強調一下幾點細節

1>(key int, value string) 和("hbase.columns.mapping" = ":key,cf1:val")以及最后insert后的select的字段,請確定順序都保持一致

2>這個hive表和hbase建立的映射就是:hbase的rowkey和hive表的select的第一個字段foo對應,而cf1是列族,val是列名,相當於已經固定好了,select查出的第二個字段就是對應的列值

3>這里 TBLPROPERTIES 定義了hbase中的表名,如果沒有這行,那么hbase默認表名就和hive表名一致

4>HbaseStorageHandler很重要,hive和hbase的集成需要將hive-hbase-handler-x.y.z.jar(x.y.z是當前環境的jar包版本)配置在Hive client auxpath路徑下,也就是說,你必須在

hive-site.xml里面配置好hive.aux.jars.path,這個屬性,而它的值是hive-hbase-handler-x.y.z.jar所在的路徑.

3.Hive映射Hbase多列族多列

類似於第一種情況,只是映射了多列族多列而已,如下

CREATE TABLE hbase_table_1(key int, value1 string, value2 int, value3 int) 
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,a:b,a:c,d:e"
);
INSERT OVERWRITE TABLE hbase_table_1 SELECT foo, bar, foo+1, foo+2 
FROM pokes WHERE foo=98 OR foo=100;

強調的細節和上面那個單列一致,只是多了幾個列族和對應的列,這里的列族和列都是提前定義好的.

scan后結果如下

hbase(main):015:0> scan "hbase_table_1"
ROW                          COLUMN+CELL                                                                      
 100                         column=a:b, timestamp=1267740457648, value=val_100                               
 100                         column=a:c, timestamp=1267740457648, value=101                                   
 100                         column=d:e, timestamp=1267740457648, value=102                                   
 98                          column=a:b, timestamp=1267740457648, value=val_98                                
 98                          column=a:c, timestamp=1267740457648, value=99                                    
 98                          column=d:e, timestamp=1267740457648, value=100                                   
2 row(s) in 0.0240 seconds

4.Hive訪問已存在的hbase表

這種方式其實hive表是個外表,即使清空hive中的表數據,Hbase中的表不會受到影響.

CREATE EXTERNAL TABLE hbase_table_2(key int, value string) 
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES ("hbase.columns.mapping" = "cf1:val")
TBLPROPERTIES("hbase.table.name" = "some_existing_table", "hbase.mapred.output.outputtable" = "some_existing_table");

5.Hive映射Hbase動態列

為啥要動態列?因為有的場景下,我需要存入hbase列族下的列名是動態的要存值的是需要查詢出來的,不是寫死的,如果沒有動態映射豈不累死,對應建表和插入如下

CREATE TABLE hbase_table_1(value map<string,int>, row_key int) 
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = "cf:,:key"
);
INSERT OVERWRITE TABLE hbase_table_1 SELECT map(bar, foo), foo FROM pokes 
WHERE foo=98 OR foo=100;

強調一下幾個細節

1>注意這里表定義mapping的時候,只定義了一個列族名為cf,還有隨后的rowkey

2>注意后面的SELECT的語句,map(bar,foo)中的bar映射的是列名,foo是列值,所以這里是動態的列插入,隨后第2個select的列對應的row_key

3>使用hive map類型時,注意SELECT查出來的字段類型和 “CREATE TABLE hbase_table_1(value map<string,int>, row_key int)”中定義的字段類型需要一致,不然無法插入,詳細解釋的話,舉個栗子

比如SELECT查出來的map(bar,foo)中列名和列值分別是varchar(50)和bigint類型的話,那么這個時候插入就會報異常然后插入失敗

 Cannot insert into target table because column number/types are different

那么怎么辦?我想到二種方式,第一種就是你定義的時候就定義好類型映射保持一致,比如你可以索性將map中的key值在hive中都定義成string類型,另外一種是cast函數,再舉個栗子,

比如SELECT查出來的map(bar,foo)中的bar是varchar(50),foo是bigint,而建立表的時候定義的map<varchar(200),bigint>,這樣依然插入不進去,那么可以進行cast,比如cast(bar as varchar(200)),ok,這樣可以解決問題.

參考資料:

https://cwiki.apache.org/confluence/display/Hive/HBaseIntegration

http://blog.cloudera.com/blog/2010/06/integrating-hive-and-hbase/

http://blog.csdn.net/xiaoshunzi111/article/details/51803719

http://blog.csdn.net/bdchome/article/details/45499641


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM