Hive与HBase的集成实践

浏览: 5417

注:若需转载,请注明出处!

Hive与HBase集成实践

大数据平台搭建 hive-2.0.0 hbase 1.1.3

环境说明

  • CentOS 6.7
  • Hadoop 2.7.2
  • Hive 2.0.0
  • HBase 1.1.3

1. 具体步骤

1. 拷贝jar包

  1. 首先删除$HIVE_HOME/lib下HBase和ZooKeeper相关的jar包
  2. 然后重新拷贝$HBASE_HOME/lib下的HBase和ZooKeeper相关的jar包至Hive下

2. 在Hive的类路径中添加一些这些jar包

有两种方式向Hive的类路径添加jar包:

  • 修改hive-site.xml中hive.aux.jars.path的值
<property>
<name>hive.aux.jars.path</name>
<value>/opt/hive-2.0.0/lib/guava-14.0.1.jar,/opt/hive-2.0.0/lib/zookeeper-3.4.6.jar,/opt/hive-2.0.0/lib/hive-hbase-handler-2.0.0.jar,/opt/hive-2.0.0/lib/hbase-common-1.1.3.jar,/opt/hive-2.0.0/lib/hbase-server-1.1.3.jar</value>
<description>The location of the plugin jars that contain implementations of user defined functions and serdes.</description>
</property>
  • 在$HIVE_HOME/conf/下新建.hiverc文件,加入下列语句:
add jar /opt/hbase-1.1.3/lib/htrace-core-3.1.0-incubating.jar;
add jar /opt/hbase-1.1.3/lib/hbase-common-1.1.3.jar;
add jar /opt/hbase-1.1.3/lib/hbase-hadoop2-compat-1.1.3.jar;
add jar /opt/hive-2.0.0/lib/hive-metastore-2.0.0.jar;
add jar /opt/hbase-1.1.3/lib/hbase-server-1.1.3.jar;
add jar /opt/hbase-1.1.3/lib/hbase-client-1.1.3.jar;
add jar /opt/hbase-1.1.3/lib/hbase-protocol-1.1.3.jar;
add jar /opt/hive-2.0.0/hcatalog/share/hcatalog/hive-hcatalog-core-2.0.0.jar;
add jar /opt/hive-2.0.0/lib/datanucleus-core-4.1.6.jar;
add jar /opt/hive-2.0.0/lib/datanucleus-api-jdo-4.2.1.jar;
add jar /opt/hive-2.0.0/lib/datanucleus-rdbms-4.1.7.jar;
add jar /opt/hive-2.0.0/lib/hive-cli-2.0.0.jar;
add jar /opt/hive-2.0.0/lib/hive-hbase-handler-2.0.0.jar;

hive在执行命令前会先读取.hiverc的文件中的内容

启动Hive 和 HBase即可使用,具体示例如第3节。

2. Hive集成HBase的原理

1. Storage Handler

  • 基本原理 
    Hive与HBase集成的实现是利用了这两者本身对外提供的API进行相互通信,这种相互通信是通过$HIVE_HOME/lib/hive-hbase-handler-2.0.0.jar工具类实现的。通过HBaseStorageHandler,Hive可以获取到Hive表所对应的HBase表名,列簇和列,InputFormat、OutputFormat类,创建和删除HBase表等。
  • 访问 
    Hive访问HBase中HTable的数据,实质上是通过MR读取HBase的数据,而MR是使用HiveHBaseTableInputFormat完成对表的切分,获取RecordReader对象来读取数据的。 
    对HBase表的切分原则是一个Region切分成一个Split,即表中有多少个Regions,MR中就有多少个Map; 
    读取HBase表数据都是通过构建Scanner,对表进行全表扫描,如果有过滤条件,则转化为Filter。当过滤条件为rowkey时,则转化为对rowkey的过滤;Scanner通过RPC调用RegionServer的next()来获取数据。

2. 使用

插入大量数据可能会由于WAL负载导致速度很慢,可以通过在插入数据之前做如下设置:

set hive.hbase.wal.enabled=false;

但是关闭WAL可能会使HBase发生错误时出现数据丢失,所以建议只有在你已有其他数据恢复策略时才使用这种设置。

若想使Hive可以访问已存在的HBase表,可以使用下面的语句创建这样的Hive表:

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" = "xyz", "hbase.mapred.output.outputtable" = "xyz");

hbase.columns.mapping是必须的,这将会和已存在的HBase表的列族进行验证,而hbase.table.name和hbase.mapred.output.outputtable是可选的。当在Hive中删除此表时,并不影响HBase中对应的表。

3. 字段映射

控制HBase字段和Hive之间的映射有两种SERDEPROPERTIES:

  • hbase.columns.mapping
  • hbase.table.default.storage.type,可以是string(default)或binary中的任一个,指定这个选项只有在Hive 0.9之后可使用.

目前所支持的字段映射多少是有些难处理或存在约束的:

  • 对于每一个Hive字段,表的创建者必须用逗号分隔的字符串(hbase.columns.mapping)指定对应的入口(Hive表有n个字段,则该字符串得指定n个入口),在各个入口之间不能由空格(因为空格会被解析成字段名中的一部分)。
  • 映射入口必须是以下两者之一:行健或’列族名:[列名][#(binary|string)]’ 
    • 如果没有指定类型,则直接使用hbase.table.default.storage.type的值
    • 合法值的的前缀也是合法的(例如#b表示#binary)
    • 如果指定某字段为binary,则对应的HBase中的单元格则应该是HBase的Bytes类的内容组成
  • 必须要有确切的行健映射
  • 如果没有指定列名,则默认使用Hive的字段名作为HBase中的列名

3. 示例

1. 多列和列族

Hive表中的3个字段与HBase中的2个列族,其中2个Hive字段(value1和value2)对应到1个HBase列族(列族a,列b和c),另1个Hive字段(e)对应到另1个HBase列族的单个列(d)。Hive建表SQL如下:

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;

此表在HBase中是这个样子的:

hbase(main):006:0> describe 'hive_hbase.hbase_table_2'
Table hive_hbase.hbase_table_2 is ENABLED
hive_hbase.hbase_table_2
COLUMN FAMILIES DESCRIPTION
{NAME => 'a', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', K
EEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER
'
, COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSI
ZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'd', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', K
EEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER
'
, COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSI
ZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s) in 0.0190 seconds

hbase(main):007:0> scan'hive_hbase.hbase_table_2'
ROW COLUMN+CELL
100 column=a:b, timestamp=1464598569847, value=val_100
100 column=a:c, timestamp=1464598569847, value=101
100 column=d:e, timestamp=1464598569847, value=102
98 column=a:b, timestamp=1464598569847, value=val_98
98 column=a:c, timestamp=1464598569847, value=99
98 column=d:e, timestamp=1464598569847, value=100
2 row(s) in 0.0200 seconds

再回到Hive中查询此表:

hive> select * from hbase_table_2;
OK
100 val_100 101 102
98 val_98 99 100
Time taken: 0.298 seconds, Fetched: 2 row(s)

2. Hive的Map字段与HBase列族

如何使用Hive的Map数据类型访问列族,每行可以有很多不同的列,而列名正好对应到Map类型字段的Keys,而列值正好对应到Map类型字段的Map值。Hive建表SQL如下:

CREATE TABLE hbase_table_3(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_3 SELECT map(bar, foo), foo FROM pokes
WHERE foo=98 OR foo=100;

这个表在HBase中是长这个样子:

hbase(main):009:0> scan'hive_hbase.hbase_table_3'
ROW COLUMN+CELL
100 column=cf:val_100, timestamp=1464600230691, value=100
98 column=cf:val_98, timestamp=1464600230691, value=98
2 row(s) in 0.0220 seconds

再回到Hive中查询此表:

hive> select * from hbase_table_3;
OK
{"val_100":100} 100
{"val_98":98} 98
Time taken: 0.163 seconds, Fetched: 2 row(s)
推荐 9
本文由 MarsJ 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

4 个评论

非常不错的集成实践,谢谢
多更新,关注这个系列,谢谢大拿分享
后续实际应用有总结了,会再更新~谢谢关注。
多更新,关注这个系列,谢谢大拿分享

要回复文章请先登录注册