本文讲解的Hive和HBase整合意思是使用Hive读取Hbase中的数据。我们可以使用HQL语句在HBase表上进行查询、插入操作;甚至是进行Join和Union等复杂查询。此功能是从Hive 0.6.0开始引入的,详情可以参见HIVE-705。Hive与HBase整合的实现是利用两者本身对外的API接口互相进行通信,相互通信主要是依靠hive-hbase-handler-1.2.0.jar工具里面的类实现的。
使用
启动
我们可以使用下面命令启动Hive,使之拥有读取Hbase的功能,如果你的Hbase只有一台机器(single-node HBase server),可以使用下面命令启动hive client:
$HIVE_HOME/bin/hive --auxpath $HIVE_HOME/lib/hive-hbase-handler-1.2.0.jar,$HIVE_HOME/lib/hbase-0.92.0.jar,$HIVE_HOME/lib/zookeeper-3.3.4.jar,$HIVE_HOME/lib/guava-r09.jar --hiveconf hbase.master=www.iteblog.com:60000 |
如果你的Hbase master是通过Zookeeper维护的,那么你可以在启动Hive Client的时候指定Zookeeper的地址:
$HIVE_HOME/bin/hive --auxpath $HIVE_HOME/lib/hive-hbase-handler-1.2.0.jar,$HIVE_HOME/lib/hbase-0.92.0.jar,$HIVE_HOME/lib/zookeeper-3.3.4.jar,$HIVE_HOME/lib/guava-r09.jar --hiveconf hbase.zookeeper.quorum=www.iteblog.com |
上面直接将Hbase相关的依赖加到启动命令行后面实在不太方便,我们可以在hive-site.xml进行配置:
< property > < name >hive.querylog.location</ name > < value >/home/iteblog/hive/logs</ value > </ property > < property > < name >hive.aux.jars.path</ name > < value > $HIVE_HOME/lib/hive-hbase-handler-1.2.0.jar, $HIVE_HOME/lib/hbase-0.92.0.jar, $HIVE_HOME/lib/zookeeper-3.3.4.jar, $HIVE_HOME/lib/guava-r09.jar </ value > </ property > < property > < name >hive.zookeeper.quorum</ name > < value >www.iteblog.com</ value > </ property > |
从Hive中创建HBase表
使用HQL语句创建一个指向HBase的Hive表
//Hive中的表名iteblog CREATE TABLE iteblog( key int , value string) //指定存储处理器 STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' //声明列族,列名 WITH SERDEPROPERTIES ( "hbase.columns.mapping" = ":key,cf1:val" ) //hbase. table . name 声明HBase表名,为可选属性默认与Hive的表名相同, //hbase.mapred. output .outputtable指定插入数据时写入的表,如果以后需要往该表插入数据就需要指定该值 TBLPROPERTIES ( "hbase.table.name" = "iteblog" , "hbase.mapred.output.outputtable" = "iteblog" ); |
通过HBase shell可以查看刚刚创建的HBase表的属性
$ 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 iteblog row(s) in 0.0530 seconds hbase(main):002:0> describe "iteblog" DESCRIPTION ENABLED { NAME => 'iteblog' , FAMILIES => [{ NAME => 'cf1' , COMPRESSION => true 'NONE' , VERSIONS => '3' , TTL => '2147483647' , BLOCKSIZE => '65536' , IN_MEMORY => 'false' , BLOCKCACHE => 'true' }]} row(s) in 0.0220 seconds hbase(main):003:0> scan "iteblog" ROW COLUMN +CELL row(s) in 0.0060 seconds |
插入数据
INSERT OVERWRITE TABLE iteblog SELECT * FROM pokes WHERE foo=98; |
在HBase端查看插入的数据
hbase(main):009:0> scan "iteblog" ROW COLUMN +CELL 98 column =cf1:val, timestamp =1267737987733, value=val_98 1 row(s) in 0.0110 seconds |
使用Hive中映射HBase中已经存在的表
创建一个指向已经存在的HBase表的Hive表
CREATE EXTERNAL TABLE iteblog2( 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" ); |
该Hive表一个外部表,所以删除该表并不会删除HBase表中的数据,有几点需要注意的是:
1、建表或映射表的时候如果没有指定:key则第一个列默认就是行键
2、HBase对应的Hive表中没有时间戳概念,默认返回的就是最新版本的值
3、由于HBase中没有数据类型信息,所以在存储数据的时候都转化为String类型
多列及多列族的映射
如下表:value1和value2来自列族a对应的b c列,value3来自列族d对应的列e:
CREATE TABLE iteblog( 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 iteblog SELECT foo, bar, foo+1, foo+2 FROM pokes WHERE foo=98 OR foo=100; |
在Hbase中看起来是这样的:
hbase(main):014:0> describe "iteblog" DESCRIPTION ENABLED { NAME => 'iteblog' , 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中查询是这样的:
hive> select * from iteblog; 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数据类型映射HBase表,这样每行都可以有不同的列组合,列名与map中的key对应,列值与map中的value对应
CREATE TABLE iteblog(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 iteblog SELECT map(bar, foo), foo FROM pokes WHERE foo=98 OR foo=100; |
cf为列族,其列名对应map中的bar,列值对应map中的foo。执行完上面的语句,在Hbase中看起来是这样的:
hbase(main):012:0> scan "iteblog" 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 |
Hive中查询是这样的:
hive> select * from iteblog; 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是作为HBase的列名使用的,所以map中的key类型必须为String类型。以下映射语句会报错:
CREATE TABLE iteblog( 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 >) |
因为map中的key必须是String,其最终需要变成HBase中列的名称。
支持简单的复合行键
如下:创建一张指向HBase的Hive表,行键有两个字段,字段之间使用~分隔
CREATE EXTERNAL TABLE iteblog( key struct<f1:string, f2:string>, value string) ROW FORMAT DELIMITED COLLECTION ITEMS TERMINATED BY '~' STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler' WITH SERDEPROPERTIES ( 'hbase.columns.mapping' = ':key,f:c1' ); |
最后,使用Hive集成HBase表的需注意以下几点:
1、对HBase表进行预分区,增大其MapReduce作业的并行度
2、合理的设计rowkey使其尽可能的分布在预先分区好的Region上
3、通过set hbase.client.scanner.caching
设置合理的扫描缓存
本文来自博客园,作者:大码王,转载请注明原文链接:https://www.cnblogs.com/huanghanyu/