Hive Hbase Integration(hive和habse的集成)

本文档翻译自官网网址
hive hbase integration
先介绍下版本信息:
hive0.9.0至少需要hbase0.92版本以上。更早的hive版本需要hbase0.89/0.90
hive1.x将与hbase0.98.x或者更低的hbase版本保持兼容。hive2.x需要hbase1.x或者更高版本。可以在这里看详细信息hive-10990 for details。如果想要hive1.x和hbase1.x集成的话,需要重新编译hive1.x。
学习的话,建议hive1.x和hbase0.98就可以了。
介绍
这篇文档包含hive hbase 集成的原始介绍。这个特征允许hive sql语句(包括select 和 insert)操作到hbase表中数据。甚至用hive本地的表通过joins和unins操作接入到hbase中。
这个hive的特征正在使用中,有建议很欢迎。555感觉翻译好僵硬。
Storage Handlers
在开始学习之后,请先看StorageHandlers,可以大楷看下storagehandlers的Hbase集成依赖整体架构。
Usage(用法)
storagehandlers是一个独立的模块,放在hive-hbase-handler-*.jar包中。在集成过程中,这个包必须放在hive客户端的用户能加载的路径中(hive和hbase都一样),Guava 和zookeeper的jar包。集成前要确保配置正确,能够连接hbase master。看The Hbase document这个连接,做一个hbase的集群。
在那里也有列子,使用客户端构建单节点的hbase服务(值得注意的在hive0.9.0和更早的版本,是jar包的路径和名字,做了一些修改)。

$HIVE_SRC/build/dist/bin/hive --auxpath $HIVE_SRC/build/dist/lib/hive-hbase-handler-0.9.0.jar,$HIVE_SRC/build/dist/lib/hbase-0.92.0.jar,$HIVE_SRC/build/dist/lib/zookeeper-3.3.4.jar,$HIVE_SRC/build/dist/lib/guava-r09.jar --hiveconf hbase.master=hbase.yoyodyne.com:60000

在这里有个例子,作用于一个分布式的hbase集群(有3个节点,3个zookeepers来选择hbase master)

$HIVE_SRC/build/dist/bin/hive --auxpath $HIVE_SRC/build/dist/lib/hive-hbase-handler-0.9.0.jar,$HIVE_SRC/build/dist/lib/hbase-0.92.0.jar,$HIVE_SRC/build/dist/lib/zookeeper-3.3.4.jar,$HIVE_SRC/build/dist/lib/guava-r09.jar --hiveconf hbase.zookeeper.quorum=zk1.yoyodyne.com,zk2.yoyodyne.com,zk3.yoyodyne.com

这个handler需要hadoop0.20或者更高的版本(推荐2.6.0吧)。这里使用了hadoop-0.20.x,hbase-0.92.0,zookeeper-3.3.4,这里仅仅用来测试。如果你不使用hbase0.92.0,你需要加入habse的版本重新编译,还要修改–auxpath。不能匹配的版本将会导致连接失败,因为hbase的rpc 协议经常改变会报MasterNotRuningExcpetion错误。
为了创建一个新的能够被hive管理的habse表,需要在hive建表语句使用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");

hbse.columns.mapping属性是必须的,将在下个部分介绍。hbase.table.name属性是可选的,这个属性代表hbase表的名字,也允许hive的表和hbase的表有不同的表名。在这个列子,hive表名为hbase_table_1,hbase的表为xyz。如果没有特殊标明(不用hbase.table.name),hive和hbase表中的表面是相同的。
在执行了这个命令知乎,你应该可以在hbase的客户端看到一个名为xyz的新的表

$ 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

注意下,在映射中有1个列val,但在hbase shell端中使用describe命名,也仅仅出现一个列族为cf1。这是因为在hbase中,仅仅列族是表级的元数据,在列族下的列仅仅显示在行级别的层次。
这里有怎么把hive的数据移动到hbase表中列子(看GetiingStart在hive中怎么创建表)

INSERT OVERWRITE TABLE hbase_table_1 SELECT * FROM pokes WHERE foo=98;

使用hbase shell 验证数据是否已经加载到表中

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

然后返回来验证hive

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

插入大量数据可能会很慢, 原因在于WAL(日志预写)的开销。如果你想关闭它,要确保你使用hive-1383(hive-0.6以上版本),然后确保在insert之前运行下面的命令。

set hive.hbase.wal.enabled=false;

警告:如果hbase 出故障了,使WAL失效可能会导致数据的丢失,所以你有其他一个恢复策略的时候才可以使用这个功能。
如果你想把hive的表接入到hbase已经存在的表,使用 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是必须的(将通过已经存在的hbase表的列族验证),然后hbase.table.name是可选的。
Columns Mapping(列族映射)
有2个SERDEPROPERTIES,用来控制hbase列和hive的映射。

  • hbase.columns.mapping
  • hbase.table.default.storage.type:能够有一个value值,string(默认)或者binary,这个选项是在hive0.9之后是可选的,在早期的版本仅仅string是可用的。
    列的映射当前支持虽然可用,但是是笨重的和有限制的。

  • 对于每一个hive的列,表的创建者必须在后面的hbase.columns.mapping中说明一个一致的映射(hive表中有n个列,这个属性的值就应该有多少个映射)。在两个映射中,空白不允许出现,因为空格将会被解读为,作为一个列族名的一部分了,这个情况你当然不希望出现。

  • 每一个映射,必须是Key或者是列族的名字格式(column-family-name:[column-name][#(binary|string)]).这个#分割符分开两个选项是在hive0.9.0增加的,在以前的版本默认就是string。1如果没有特别的类型值,hbase.table.default.storage.type将会被使用。2任何有效值得前缀都是有点的(使用#b来代替#binary).3如果在映射中,你指定了一个列为binary,hbase的列也希望是 bytes类型的。
  • 必须有一个key映射,这个可以是一个key或者是一个结构列,看simple compositecomplex composite keys 来实现复杂的主键。
  • 说明下,在hive-1228 hive0.6之前,key是不支持的,hive表的第一列隐试转换成Key,hive0.6之后,强力建议,自己显示的指定key,以后将会删除隐式转换的映射特征了。
  • 如果没有列名设置,这hive的列将会映射到相应hbase表的所有列族中。hive map数据类型现在没有办法映射到hbase的列族中。
  • 因为hbase没有关联列的数据类型信息,所以在存储到hbase中之前,都会转换成string类型。这里没有办法转换用户自定义的数据类型。
  • hive表不需要映射hbase的所有列族,但是Hbase表中那些没有映射的列簇很难通过hive表接入,但是可以通过多个hive表映射同一个hbase表。
    下面的部分提供了详细的列子,关于现在的列的映射。
    下面有个列子,hive的map数据类型被使用来介入hbase的列族。每一行有许多不同的列的集合,集合中列的名称和map的keys映射,map中的值和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;

这里列中也演示了,hive的列不一定是第一列作为Hbase的row key。
下面是在Hbase中看到的情况(在不同的行,有不同的列明)、

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

然后在Hive中查询下

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数据类型,因为它被使用为hbase的列名,所以下面的表的定义是错误的。

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>)

hive的map对应habse 列的前缀
注意下,在hive0.12以后,通配符也能够被使用在查询列中。例如,如果你想查询hbase中所有的列,你可以使用’col_prefix’前缀,像下面的查询就可以使用。

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:col_prefix.*,:key"
);

相同的限制条件如下,那就是Map的key应该是string类型,它映射到Hbase的列名,map的值可以你自己查询的类型。其他的限制是所有的在前缀中设定的值应该是相同类型的。那就是,value的所有类型要不是都是int或者都是string。
隐藏列的前缀
在hive1.3.0之后,在你查询的时候可以隐藏前缀。有一个serde布尔属性,hbase.columns.mapping.prefix.hide(默认是false),它定义了在hive的map中的keys是否应该隐藏。

CREATE TABLE hbase_table_1(tags map<string,int>, row_key string) 
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = "cf:tag_.*,:key",
"hbase.columns.mapping.prefix.hide" = "true"
);

在Hive中查询,这个列tags的值如下:
“x” : 1
而不是
“tag_x” : 1
非法情况:在使用hive的原生数据类型对应hbase的列族时候
如下表定义是非法的,因为一个Hive的列映射一个列族必须是map类型才行。

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.table.default.storage.type的默认值:

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"
);

指定hbase.table.default.storage.type为binary:

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"
);

简单的复合主键
通过hive的数据类型struct映射到hbase的row key,Hive能够读和写有分隔符的复合主键。使用row format delimited….collection items terminated by,列如:

-- Create a table with a composite row key consisting of two string fields, delimited by '~'
CREATE EXTERNAL TABLE delimited_example(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');

复杂复合主键和HBaseKeyFactory
从hive0.14.0开始hive支持复杂主键,可以看下面链接hive-2599看不同点。
对于一个复杂主键的使用列子,hive允许用户自己定义一个HbaseKeyFactory,它使用hive的stuct来定义key到多个hive列的映射。在serdeproperties选择中可以使用hbase.composite.key.factory属性来配置。

-- Parse a row key with 3 fixed width fields each of width 10
-- Example taken from: https://svn.apache.org/repos/asf/hive/trunk/hbase-handler/src/test/queries/positive/hbase_custom_key2.q
CREATE TABLE hbase_ck_4(key struct<col1:string,col2:string,col3:string>, value string)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
    "hbase.table.name" = "hbase_custom2",
    "hbase.columns.mapping" = ":key,cf:string",
    "hbase.composite.key.factory"="org.apache.hadoop.hive.hbase.SampleHBaseKeyFactory2");

hbase.composite.key.factory应该写应用的HbaseKeyFactory的全路径名,看看sampleHbaseKeyFacroty2来看详情。为了测试成功,这个工厂类必须要在你的classpath中。注意:要在兼容的地反使用它,这个功能现阶段仅仅用在测试环境。
映射 Timestamps数据类型
如果使用Hive hbase默认的timestamp插入hbase的表中,通常是当前的时间戳。在表的基础,这个可能会被拒绝,当表使用serdeproperties选项的habse.put.timestamp,它必须验证由想的timestamp或者是-1 (用来默认的策略)。
key的唯一性
hive表和hbase有一个微妙的不同,就是habse表由唯一性主键,而hive没有。当多个由相同主键的行插入到Hbase表中时,只有1个行会被存储(这个选择策略是任意的,所以不要依赖Hbase来选择正确的那一行)。这点和hive是冲突的,hive很愉快存储相同key不同value的多行数据。
列如,这pokes表包含了相同key的多行,如果拷贝到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中,多个副本会消失,只保留一个

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;

覆盖
habse映射hive表和其他hive表的另一个不同是 insert overwrite使用时,已经存在的行没有从表中删除,而是,如果keys相同,存在的行会被重写。
潜在的续集
有许多地方值得注意,在使用hive hbase集成的时候:

  • 在hive-806,hive-1245中,有更灵活的列的映射
  • 在没有给定映射的情况下,使用默认的映射
  • 多层过滤和索引(看filterpushdowndev)和indexdev
  • timestamp字段,可能会支持把他作为分区的key
  • 允许肩膀是使用hbase.master的配置
  • 运行分析其和最小化表的列映射开销
  • 使用自定义的规范来查询和加载数据,通过hbase的客户端api
  • 日志是非常烦人的,有许多列外,研究这些或者修复它们。
    构建
    storage handler的代码位于:hive/trunk/hbase-hanlder
    hbase和zookeeper依赖是通过ivy(dependency manager)获取。

本文是翻译的Hive的wiki,Hive hbase intergration官方文档,网址如下官网
翻译有点生硬,欢迎指正修改,我自己以后也会修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值