Hive整合HBase

Hive支持使用HDFS之外的存储系统作为底层存储系统,其中官方明确支持HBase,Kudu,Druid和JDBC(MySQL等)。

Hive提供了相应的接口 StorageHandlers,用以实现和其他存储系统的整合。本人整理的已有相应实现的其他存储系统有:Phoenix HBase,MongoDB,ElasticSearch等。

本文主要讨论Hive整合HBase在使用上的一些关键内容,更详细的内容请参考 HBaseIntegration

介绍

Hive整合HBase之后,可以通过Hive QL语法读写HBase表,并且可以和Hive的本地表进行join和union。

不过需要注意的是,虽然可以通过Hive QL读写HBase表,但是Hive QL操作是下推到HBase操作,所以在编写Hive QL时,需要依照HBase的数据操作思维,否则性能表现可能会比较差。

经过本人的简单测试,当通过Hive QL进行过滤操作时,使用HBase rowkey,性能表现很好,但是如果使用其他的列,性能表现非常糟糕。

基础知识

StorageHandlers

StorageHandlers 是Hive提供的整合其他存储系统的接口,最初是 HBaseIntegration 的一部分,后面抽象出来,成为一个通用接口。

该接口主要规范了以下几个部分:

  • input formats

  • output formats

  • serialization/deserialization libraries

之后也可以实现 metadata hook 接口,允许Hive DDL管理目标存储系统。

术语

这里有几个术语需要了解一下。

Hive有 managed vs external 两种表,这里不做介绍。

StorageHandlers有两个新增的概念:native vs non-native

一个 native 表是没有 storage handler 的表。

一个 non-native 表是带有 storage handler 的表。

当创建一个 non-native 表时,使用 STORED BY 子句指定。

需要注意,官网提到:

When STORED BY is specified, then row_format (DELIMITED or SERDE) and STORED AS cannot be specified.

我的理解是,STORED BYROW FORMAT and STORED AS 是二选一的,不能同时使用。

这个理解可能不对,因为在下文的HBaseIntegration基本使用中,出现了ROW FORMATSTORED BY同时存在的情况。

HBaseIntegration依赖包

HBaseIntegration的实现是在Hive工程的一个子工程(hbase-handler)下,如果要使用这个特性,需要编译这个子工程,编译结果如 hive-hbase-handler-x.y.z.jar,这个jar需要添加到Hive client auxpath中,并进行相应的配置,具体操作请看 Usage

在CDH中,这个特性是直接可用的,不需要进行编译和配置。

基础用法

创建一个被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");

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

hbase.columns.mapping 属性是必要的,用来映射HBase表列到Hive表列,下面重点说明。

hbase.table.name 属性是可选的,用来指定HBase表名,如果不指定,则Hive和HBase的表名将是一致的。

hbase.mapred.output.outputtable 属性是可选的,如果你打算插入数据到表,则使用这个属性指定HBase表名。

列映射

有两个 SERDEPROPERTIES 用来控制HBase列到Hive的映射:

  • hbase.columns.mapping :指定HBase列,用于和Hive表列进行映射。

  • hbase.table.default.storage.type :指定默认存储类型。可指定类型有两种,stringbinary,其中默认类型是string

当前对于列映射的支持有一些约束,在使用上需要注意:

  • hbase.columns.mapping 指定的列是一个以英文逗号分隔的字符串,空格会被认为是列名的一部分。

  • Hive表的列必须和 hbase.columns.mapping 指定的列一一对应。

  • hbase.columns.mapping 指定的每个映射列必须是 :key:timestamp 或者是 column-family-name:[column-name][#(binary|string)]格式的一种。其中 :key 对应 rowkey:timestamp对应 timestampcolumn-family-name:[column-name][#(binary|string)]格式用来指定具体的列。#用来指定列的类型,如果不指定列类型,则默认使用 hbase.table.default.storage.type 值,任何有效值的前缀是有效的,例如可以用 #b代替 #binary

  • :key 必须是准确的,可能是一个字符串或者一个结构体。:key可以不指定,这时Hive表第一列对应rowkey,但是建议显式指定 :key,因为在未来,将不再支持隐式映射rowkey

  • 如果不指定列名,那么Hive表的相应列将映射HBase表整个列簇,Hive表的相应列必须是MAP类型,MAP的key的类型必须是string

  • 从HBase 1.1开始,支持了使用 :timestamp 访问HBase timestamp,但是相应的Hive表列的类型需要是 bigint 或者 timestamp

  • 在一个Hive表中,不必映射每个HBase列簇,但是未映射的列簇无法通过Hive表进行访问。可以将同一个HBase表映射成多个Hive表,这种做法在实际应用中或许会更方便。

其他

在实际使用中,Hive本地表和Hive映射的HBase表可以进行一定程度的互操作。

例如从Hive中移动数据到HBase中:

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

对于Hive-HBase映射表,使用Hive或HBase都可以操作数据。

因为HBase的WAL,插入大量数据的时候,可能会比较慢,可以通过关闭WAL来提高写入速度,但是可能导致数据丢失。

关闭WAL的指令如下:

set hive.hbase.wal.enabled=false;

另外,HBase rowkey是唯一的,Hive映射表的操作也会遵循这个特性。

更多用法

多列和列簇

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

Hive MAP映射HBase列簇

使用Hive 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"
);

value列映射了HBase cf列簇,每行可能有不同的列集。

需要注意,map<string, int> 中,key的类型必须是string,value的类型需要保持一致。

Hive MAP映射HBase列前缀

使用通配符可以匹配HBase列,实现在Hive中映射指定前缀的列集:

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<string, int> 中,key的类型必须是string,value的类型需要保持一致。

隐藏列前缀

有一个 hbase.columns.mapping.prefix.hide 属性,默认为false,如果设置为 true,则可以在查询结果中隐藏列前缀,示例如下:

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

此时查询tags列时,结果如下:

"x": 1

如果未启用隐藏列前缀属性,查询结果应该如下:

"tag_x": 1

指定列类型

使用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值:

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

简单复合Row Keys

还可以使用Hive结构体映射rowkey,假设rowkey是由两个字符串拼接来的,连接符是~,可以通过ROW FORMAT DELIMITED...COLLECTION ITEMS TERMINATED BY拆分rowkey,示例如下:

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

更多

还支持更多的使用方法,比如复杂复合Row KeysHBase列使用Avro序列化类型等。

更多内容请参考 HBaseIntegration

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值