您好,登錄后才能下訂單哦!
此篇文章基于hive官方英文文檔翻譯,有些不好理解的地方加入了我個(gè)人的理解,官方的英文地址為:
1.https://cwiki.apache.org/confluence/display/Hive/StorageHandlers
2.https://cwiki.apache.org/confluence/display/Hive/HBaseIntegration
一 存儲(chǔ)處理器介紹
通過(guò)HIVE存儲(chǔ)處理器,不但可以讓hive基于hbase實(shí)現(xiàn),還可以支持cassandra JDBC MongoDB 以及 Google Spreadsheets
HIVE存儲(chǔ)器的實(shí)現(xiàn)原理基于HIVE以及Hadoop的可擴(kuò)展性實(shí)現(xiàn):
輸入格式化(input formats)
輸出格式化(output formats)
序列化/反序列化包(serialization/deserialization librarises)
除了依據(jù)以上可擴(kuò)展性,存儲(chǔ)處理器還需要實(shí)現(xiàn)新的元數(shù)據(jù)鉤子接口,這個(gè)接口允許使用HIVE的DDL語(yǔ)句來(lái)定義和管理hive自己的元數(shù)據(jù)以及其它系統(tǒng)的目錄(此目錄個(gè)人理解為其它系統(tǒng)的元數(shù)據(jù)目錄)
一些術(shù)語(yǔ):
HIVE本身有的概念:
被管理的表即內(nèi)部表(managed):元數(shù)據(jù)由hive管理,并且數(shù)據(jù)也存儲(chǔ)在hive的體系里面
外部表(external table):表的定義被外部的元數(shù)據(jù)目錄所管理,數(shù)據(jù)也存儲(chǔ)在外部系統(tǒng)中
hive存儲(chǔ)處理器的概念:
本地(native)表:hive不需要借助存儲(chǔ)處理器就可以直接管理和訪問(wèn)的表
非本地(non-native)表:需要通過(guò)存儲(chǔ)處理器才能管理和訪問(wèn)的表
內(nèi)部表 外部表 和 本地表 非本地表 形成交叉,就有了下面四種形式的概念定義:
被管理的本地表(managed native):通過(guò)CREATE TABLE創(chuàng)建的表
外部本地表(external native):通過(guò)CREATE EXTERNAL TABLE創(chuàng)建,但是沒(méi)有帶STORED BY子句
被管理的非本地表()managed non-native):通過(guò)CREATE TABLE 創(chuàng)建,同時(shí)有STORED BY子句,hive在元數(shù)據(jù)中存儲(chǔ)表定義,但是不創(chuàng)建任何文件(我的理解是存放數(shù)據(jù)的目錄文件,hive在定義好表結(jié)構(gòu)后會(huì)創(chuàng)建對(duì)應(yīng)的目錄來(lái)存儲(chǔ)對(duì)應(yīng)的數(shù)據(jù)),hive存儲(chǔ)處理器向存儲(chǔ)數(shù)據(jù)的系統(tǒng)發(fā)出一個(gè)請(qǐng)求來(lái)創(chuàng)建一個(gè)一致的對(duì)象結(jié)構(gòu);
外部非本地(external non-native):通過(guò)CREATE EXTERNAL TABLE創(chuàng)建,并且?guī)в?/span>STORED BY子句;hive在自己的元數(shù)據(jù)中注冊(cè)表的定義信息,并且通過(guò)調(diào)用存儲(chǔ)處理器來(lái)檢查這些注冊(cè)在hive中的信息是否與其它系統(tǒng)中原來(lái)定義的信息一致
通過(guò)hive創(chuàng)建表結(jié)構(gòu)的DDL語(yǔ)句:
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [col_comment], col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name, ...)] INTO num_buckets BUCKETS]
[
[ROW FORMAT row_format] [STORED AS file_format]
| STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)]
]
[LOCATION hdfs_path]
[AS select_statement]
具體的使用樣例,會(huì)在下面詳細(xì)說(shuō)明
二 Hive與Hbase的整合
hive和Hbase的整合通過(guò)Hbase handler jar包實(shí)現(xiàn),它的形式為hive-hbase-x.y.z.jar ,這個(gè)處理器需要依賴hadoop0.20以上版本,并且只在hadoop-0.20.x hbase-0.92.0 和zookeeper-3.3.4 上進(jìn)行過(guò)測(cè)試。如果hbase版本不是0.92則需要基于你使用的版本重新編譯對(duì)應(yīng)的hive存儲(chǔ)處理器。
為了創(chuàng)建一張可以被hive管理的hbase的表,需要在hive的ddl語(yǔ)句CREATE TABLE 后面加入語(yǔ)句STORED BY
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.table.name屬性是可選的,用它來(lái)指定此表在hbase中的名字,這就是說(shuō),允許同一個(gè)表在hive和hbase中有不同的名字。上述語(yǔ)句中,在hive中的表名叫hbase_talbe_1,在hbase中,此表名叫xyz。如果不指定,兩個(gè)名字則會(huì)是相同的。
當(dāng)執(zhí)行完命令后,就可以在HBase的shell中看到一張新的空表,如下:
$ hbase shell
HBase Shell; enter 'help<RETURN>' for list of supported commands.
Version: 0.20.3, r902334, Mon Jan 25 13:13:08 PST 2010
hbase(main):001:0> list
xyz
1 row(s) in 0.0530 seconds
hbase(main):002:0> describe "xyz"
DESCRIPTION ENABLED
{NAME => 'xyz', FAMILIES => [{NAME => 'cf1', COMPRESSION => 'NONE', VE true
RSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY =>
'false', BLOCKCACHE => 'true'}]}
1 row(s) in 0.0220 seconds
hbase(main):003:0> scan "xyz"
ROW COLUMN+CELL
0 row(s) in 0.0060 seconds
上面的輸出中沒(méi)有列val的信息,雖然在建表語(yǔ)句中已經(jīng)指定了這個(gè)列名。這是因?yàn)樵?/span>hbase中只有列族的名字才會(huì)被定義在表級(jí)的元數(shù)據(jù)中,列族中的列只定義在行級(jí)別的元數(shù)據(jù)中。
下面的語(yǔ)句是定義怎么把數(shù)據(jù)從hive中加載進(jìn)入HBase的表,表pokes是hive中已經(jīng)存在的一個(gè)表,并且表中有數(shù)據(jù)。
INSERT OVERWRITE TABLE hbase_table_1 SELECT * FROM pokes WHERE foo=98;
然后,在Hbase shell中驗(yàn)證數(shù)據(jù)是否已經(jīng)加載:
hbase(main):009:0> scan "xyz"
ROW COLUMN+CELL
98 column=cf1:val, timestamp=1267737987733, value=val_98
1 row(s) in 0.0110 seconds
通過(guò)hive的語(yǔ)句查詢表的結(jié)果如下:
hive> select * from hbase_table_1;
Total MapReduce jobs = 1
Launching Job 1 out of 1
...
OK
98 val_98
Time taken: 4.582 seconds
Inserting large amounts of data may be slow due to WAL overhead; if you would like to disable this, make sure you have HIVE-1383 (as of Hive 0.6), and then issue this command before the INSERT:
set hive.hbase.wal.enabled=false;
Warning: disabling WAL may lead to data loss if an HBase failure occurs, so only use this if you have some other recovery strategy available.
如果想基于已經(jīng)存在的hbase表創(chuàng)建hive可訪問(wèn)的表,則需要用CREATE EXTERNAL TABLE,如下:
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.columns.mapping屬性項(xiàng)是必須存在的,它代表的是hbase表的列族以及列的定義信息。
hive與hbase的列匹配
有兩種SERDEPROPERTIES配置信息來(lái)控制HBase列到HIve的映射
1.hbase.columns,mapping
2.hbase.table.default.storage.type
這個(gè)屬性可以有String和二進(jìn)制兩種類型的值,默認(rèn)是String;這個(gè)選項(xiàng)只有在hive0.9這個(gè)版本可用, 并且在早期的版本中,只有String類型可用
當(dāng)前列匹配使用起來(lái)顯得有點(diǎn)笨重和憋手:
1.每個(gè)hive的列,都需要在參數(shù)hbase.columns.mapping中指定一個(gè)對(duì)應(yīng)的條目(比如:a:b或者:key就叫一個(gè)條目),多個(gè)列之間的條目通過(guò)逗號(hào)分隔;也就是說(shuō),如果某個(gè)表有n個(gè)列,則參數(shù)hbase.columns.mapping的值中就有n個(gè)以逗號(hào)分隔的條目。比如:
"hbase.columns.mapping" = ":key,a:b,a:c,d:e" 代表有兩個(gè)列族,一個(gè)是a一個(gè)是d,a列族中有兩列,分別為b和c
注意,hbase.columns.mapping的值中是不允許出現(xiàn)空格的
2.每個(gè)匹配條目的形式必須是:key或者列族名:[列名][#(binary|string)](前面帶有#標(biāo)識(shí)的是在hive0.9才添加的,早期的版本把所有都當(dāng)作String類型)
1)如果沒(méi)有給列或者列族指定類型,hbase.table.default.storage.type的值會(huì)被當(dāng)作這些列或者列族的類 型
2)表示類型的值(binary|string)的任何前綴都可以被用來(lái)表示這個(gè)類型,比如#b就代表了#binary
3)如果指定列的類型為二進(jìn)制(binary)字節(jié),則在HBase的單元格的存儲(chǔ)類型也必須為二進(jìn)制字節(jié)
3.必須竄至一個(gè):key的形式匹配條目(不支持復(fù)合key的形式)
4.在hive0.6版本以前,是通過(guò)第一個(gè)條目來(lái)作為關(guān)鍵字(key)字段,從0.6以后,都需要直接通過(guò):key的方式來(lái)指定
5.當(dāng)前沒(méi)有辦法可以訪問(wèn)到HBase的時(shí)間撮屬性,并且查詢總是訪問(wèn)到最新的數(shù)據(jù)(這條主要是因?yàn)?/span>hbase單元格數(shù)據(jù)存儲(chǔ)是有版本的,根據(jù)時(shí)間撮)
6. 因?yàn)?/span>HBase的列定義沒(méi)有包含有數(shù)據(jù)類型信息,所以在存儲(chǔ)的時(shí)候,會(huì)把所有的其它類型都轉(zhuǎn)換為string 代表;所以,列數(shù)據(jù)類型不支持自定義
7. 沒(méi)有必要對(duì)HBase的所有列族都進(jìn)行映射,但是沒(méi)有被映射的列族不能通過(guò)訪問(wèn)Hive表讀取到數(shù)據(jù);可以把多個(gè)Hive表映射到同一個(gè)HBase的表
下面的章節(jié)提供更加詳細(xì)的例子,來(lái)說(shuō)明當(dāng)前各種不同的列映射
多個(gè)列和列族
下面的例子包含三個(gè)Hive表的列以及兩個(gè)HBase表的列族,其中一個(gè)列族包括兩個(gè)列
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;
上面的例子中,hive擁有除去可以外的列為三個(gè),value1 value2 value3,對(duì)應(yīng)的HBase表為兩個(gè)列族,分別為a和d,其中a包括兩列(b和c);值的對(duì)應(yīng)關(guān)系從左到右一一對(duì)應(yīng),a列族中的b列對(duì)應(yīng)value1,c列對(duì)應(yīng)value2,d列族的e列對(duì)應(yīng)value3
下面是從HBase中查看的結(jié)果:
hbase(main):014:0> describe "hbase_table_1"
DESCRIPTION ENABLED
{NAME => 'hbase_table_1', FAMILIES => [{NAME => 'a', COMPRESSION => 'N true
ONE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_M
EMORY => 'false', BLOCKCACHE => 'true'}, {NAME => 'd', COMPRESSION =>
'NONE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN
_MEMORY => 'false', BLOCKCACHE => 'true'}]}
1 row(s) in 0.0170 seconds
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
同一張表在Hive中的查詢結(jié)果是:
hive> select * from hbase_table_1;
Total MapReduce jobs = 1
Launching Job 1 out of 1
...
OK
100 val_100 101 102
98 val_98 99 100
Time taken: 4.054 seconds
Hive MAP(集合)與Hbase 列族的映射
下面是Hive的MAP數(shù)據(jù)類型與Hbase列族的映射例子。每行都可以包含不同的列組合,列名與map的可以對(duì)應(yīng),values與列值對(duì)應(yīng)。
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;
其中cf表示列族,冒號(hào)后面為空,它與Hive表的列value對(duì)應(yīng),即value的key為cf列族的列,可以通過(guò)下面HBase的查詢來(lái)理解key為列名,value為值的用法。
hbase(main):012:0> scan "hbase_table_1"
ROW COLUMN+CELL
100 column=cf:val_100, timestamp=1267739509194, value=100
98 column=cf:val_98, timestamp=1267739509194, value=98
2 row(s) in 0.0080 seconds
cf為列族名,val_100為hive表中MAP(集合)的key,100為MAP(集合)中的val_100的值
下面是對(duì)應(yīng)的hive的查詢顯示結(jié)果:
hive> select * from hbase_table_1;
Total MapReduce jobs = 1
Launching Job 1 out of 1
...
OK
{"val_100":100} 100
{"val_98":98} 98
Time taken: 3.808 seconds
注意:MAP(集合)的key必須是string類型,否則會(huì)失敗,因?yàn)?/span>key是HBase列的名字;如下的定義將會(huì)失敗
CREATE TABLE hbase_table_1(key int, value map<int,int>)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,cf:"
);
FAILED: Error in metadata: java.lang.RuntimeException: MetaException(message:org.apache.hadoop.hive.serde2.SerDeException org.apache.hadoop.hive.hbase.HBaseSerDe: hbase column family 'cf:' should be mapped to map<string,?> but is mapped to map<int,int>)
注意:當(dāng)hbase.columns.mapping中有“:key,cf:”這樣的值,即列族冒號(hào)后面為空時(shí),表示Hive中對(duì)應(yīng)的類型為集合map,如果不是,則創(chuàng)建表會(huì)失敗
CREATE TABLE hbase_table_1(key int, value string)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,cf:"
);
FAILED: Error in metadata: java.lang.RuntimeException: MetaException(message:org.apache.hadoop.hive.serde2.SerDeException
org.apache.hadoop.hive.hbase.HBaseSerDe: hbase column family 'cf:' should be mapped to map<string,?> but is mapped to string)
hbase.columns.mapping中值類型用法列舉
如果沒(méi)有指定值的類型,比如cf:val,則采用配置hbase.table.default.storage.type的值為數(shù)據(jù)類型
1.當(dāng)不配置hbase.table.default.storage.type時(shí),它默認(rèn)是string,如果有二進(jìn)制的數(shù)據(jù)類型,則如下定義:
CREATE TABLE hbase_table_1 (key int, value string, foobar double)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key#b,cf:val,cf:foo#b"
);
2.如果顯示的指定hbase.table.default.storage.type為binary時(shí),如果類型有string類型,則需要指定,如:
CREATE TABLE hbase_table_1 (key int, value string, foobar double)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,cf:val#s,cf:foo",
"hbase.table.default.storage.type" = "binary"
);
cf:val#s 中的#s就表示類型為string,cf:foo沒(méi)有配置類型,則采用hbase.table.default.storage.type的配置,為binary
添加時(shí)間戳
當(dāng)用hive給HBase的表添加記錄時(shí),時(shí)間戳默認(rèn)為當(dāng)前時(shí)間,如果想改變這個(gè)值,可以通過(guò)設(shè)置SERDEPROPERIES屬性的可選配置項(xiàng)hbase.put.timestamp,當(dāng)這個(gè)配置項(xiàng)為-1的時(shí)候,就是默認(rèn)策略,即添加記錄為當(dāng)前時(shí)間戳
CREATE TABLE hbase_table_1 (key int, value string, foobar double)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,cf:val#s,cf:foo",
"hbase.table.default.storage.type" = "binary"
"hbase.put.timestamp" = "2013-03-17 09:04:30"
)
主鍵唯一性
HBase與Hive的表有一個(gè)細(xì)微的差別,就是HBase的表有一個(gè)主鍵,并且需要唯一,但是Hive沒(méi)有;如果不能保證這個(gè)主鍵的唯一,則HBase存儲(chǔ)的時(shí)候,只能存儲(chǔ)其中一個(gè),這會(huì)導(dǎo)致查詢的時(shí)候,hive總能找到正確的值,而HBase出來(lái)的結(jié)果就不確定
如下,在hive中查詢:
CREATE TABLE pokes2(foo INT, bar STRING);
INSERT OVERWRITE TABLE pokes2 SELECT * FROM pokes;
-- this will return 3
SELECT COUNT(1) FROM POKES WHERE foo=498;
-- this will also return 3
SELECT COUNT(1) FROM pokes2 WHERE foo=498;
同一張表在HBase中查詢,就會(huì)出來(lái)不確定的結(jié)果:
CREATE TABLE pokes3(foo INT, bar STRING)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,cf:bar"
);
INSERT OVERWRITE TABLE pokes3 SELECT * FROM pokes;
-- this will return 1 instead of 3
SELECT COUNT(1) FROM pokes3 WHERE foo=498;
覆蓋(Overwrite)
當(dāng)執(zhí)行OVERWRITE時(shí),HBase中已經(jīng)存在的記錄是不會(huì)被刪除的;但是,如果存在的記錄與新紀(jì)錄的主鍵(key)是一樣的,則老數(shù)據(jù)會(huì)被覆蓋
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。