On this page
Hive HBase 集成
Version information
Version information
Hive 1.x 将 continue 与 HBase 0.98.x 和更低版本兼容。 Hive 2.x 将与 HBase 1.x 及更高版本兼容。 (有关详细信息,请参见HIVE-10990。)想要使用 Hive 1.x 使用 HBase 1.x 的 Consumer 将需要自己编译 Hive 1.x 流代码。
Introduction
本页记录了最初在HIVE-705中引入的 Hive/HBase 集成支持。此功能允许 Hive QL 语句访问HBase表以进行读取(SELECT)和写入(INSERT)。甚至可以通过联接和联合将对 HBase 表的访问与本机 Hive 表结合。
HBase HUG10 聚会提供了演示文稿
此功能正在进行中,欢迎对其进行改进的建议。
Storage Handlers
在 continue 之前,请阅读StorageHandlers以获得 HBase 集成所依赖的通用存储处理程序框架的概述。
Usage
存储处理程序是作为独立模块hive-hbase-handler-x.y.z.jar
构建的,该模块必须与 HBase,Guava 和 ZooKeeper jar 一起在 HiveClient 端 auxpath 上可用。它还需要设置正确的配置属性才能连接到正确的 HBase 主站。有关如何设置 HBase 群集的信息,请参见HBase 文档。
这是一个在源构建环境中使用 CLI 的示例,它以单节点 HBase 服务器为目标。 (请注意,jar 的位置和名称在 Hive 0.9.0 中已更改,因此对于较早的版本,需要进行一些更改.)
$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 位动物园 Management 员的法定人数选举 HBase 主服务器:
$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
该处理程序需要 Hadoop 0.20 或更高版本,并且仅已使用依赖版本 hadoop-0.20.x,hbase-0.92.0 和 zookeeper-3.3.4 进行了测试。如果您未使用 hbase-0.92.0,则需要使用与您的版本匹配的 HBase jar 来重建处理程序,并相应地更改上面的--auxpath
。由于 HBase RPC 协议经常更改,因此无法使用匹配版本会导致误导连接失败,例如 MasterNotRunningException。
为了创建要由 HiveManagement 的新 HBase 表,请使用CREATE TABLE
上的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.mapred.output.outputtable" = "xyz");
hbase.columns.mapping
属性是必需的,将在下一部分中进行说明。 hbase.table.name
属性是可选的;它控制 HBase 已知的表名,并允许 Hive 表具有不同的名称。在此示例中,该表在 Hive 中被称为hbase_table_1
,在 HBase 中被称为xyz
。如果未指定,则 Hive 和 HBase 表名称将相同。 hbase.mapred.output.outputtable
属性是可选的;如果您打算将数据插入表中,则需要此属性(hbase.mapreduce.TableOutputFormat
使用该属性)
执行完上述命令后,您应该能够在 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
注意,即使在 Map 中指定了列名“ val”,在 HBase shell 的 DESCRIBE 输出中也只有列族名“ cf1”出现。这是因为在 HBase 中,表级元数据中仅列族(而非列)是已知的。列族中的列名称仅在每行级别显示。
以下是将数据从 Hive 移到 HBase 表中的方法(有关如何在 Hive 中首先创建示例表pokes
的信息,请参见GettingStarted):
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.mapred.output.outputtable" = "some_existing_table");
同样,hbase.columns.mapping
是必需的(并将针对现有 HBase 表的列族进行验证),而hbase.table.name
是可选的。 hbase.mapred.output.outputtable
是可选的。
Column Mapping
有两个SERDEPROPERTIES
控制 HBase 列到 Hive 的 Map:
hbase.columns.mapping
hbase.table.default.storage.type
:值可以为string
(默认值)或binary
,此选项仅在 Hive 0.9 及更高版本中可用,并且string
行为是早期版本中唯一可用的选项
当前可用的列 Map 支持有些繁琐且受限:
对于每个 Hive 列,表创建者必须在逗号分隔的
hbase.columns.mapping
字符串中指定一个对应的条目(因此,对于具有* n 列的 Hive 表,该字符串应具有 n *个条目);不应在条目之间使用空格,因为它们将作为列名的一部分被插入,这几乎肯定不是您想要的Map 条目必须为
:key
,:timestamp
或column-family-name:[column-name][#(binary|string)
的形式(在 Hive 0.9.0中添加了用*#*分隔的类型说明,早期版本将所有内容解释为字符串)如果未给出类型说明,则将使用
hbase.table.default.storage.type
中的值有效值的任何前缀也都是有效的(即
#b
而不是#binary
)如果将一列指定为
binary
,则相应的 HBase 单元中的字节应采用 HBase 的Bytes
类产生的形式。
(请注意,在 Hive 0.6 中的HIVE-1228之前,不支持
:key
,并且第一个 Hive 列隐式 Map 到键;从 Hive 0.6 开始,现在强烈建议您始终明确指定键;我们将不再支持隐式键将来 Map)如果没有给出列名,则 Hive 列将 Map 到相应 HBase 列族中的所有列,并且 Hive MAP 数据类型必须用于允许访问这些(可能是稀疏的)列
从 HBase 1.1(HBASE-2828)开始,有一种使用特殊的
:timestamp
Map 访问 HBase 时间戳属性的方法。它必须是bigint
或timestamp
。不必引用每个 HBase 列族,但是未 Map 的 HBase 列族将无法通过 Hive 表访问;可以将多个 Hive 表 Map 到同一个 HBase 表
接下来的几节提供了当前可能的各种列 Map 的详细示例。
多个列和系列
这是一个具有三个 Hive 列和两个 HBase 列族的示例,其中两个 Hive 列(value1
和value2
)对应于一个列族(a
,HBase 列名称为b
和c
),另一个 Hive 列对应于自己的列族(d
)中的单个列(e
)。
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):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 时:
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 数据类型可用于访问整个列族的方式。每行可以具有一组不同的列,其中列名对应于 Map 键,列值对应于 Map 值。
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 行键.)
这是在 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 的键必须具有数据类型字符串,因为它用于命名 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 到 HBase 列前缀
另请注意,以Hive 0.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 的键应该是一个字符串,因为它 Map 到 HBase 列名,并且值可以是您要检索的值的类型。另一个限制是,给定前缀下的所有值都应为同一类型。也就是说,它们都应为“ int”类型或“ string”类型,依此类推。
隐藏列前缀
从Hive 1.3.0开始,可以在选择查询结果中隐藏列前缀。有一个 SerDe 布尔属性 hbase.columns.mapping.prefix.hide(默认为 false),它定义是否在 HiveMap 的键中隐藏该前缀:
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"
);
然后,“标签”(select tags from hbase_table_1
)列的值将为:
"x" : 1
instead of:
"tag_x" : 1
非法:Hive 原始到 HBase 列系列
如下表定义是非法的,因为
Map 到整个列族的 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
:
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"
);
简单的复合行键
Version information
通过将 HBase 行键 Map 到 Hive 结构,并使用 ROW FORMAT DELIMITED ... COLLECTION ITTES TERMINATED BY,Hive 可以将定界的组合键读写到 HBase。例:
-- 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
对于更复杂的用例,Hive 允许用户指定一个 HBaseKeyFactory,它定义键到 Hive 结构中字段的 Map。可以使用 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.mapred.output.outputtable" = "hbase_custom2",
"hbase.columns.mapping" = ":key,cf:string",
"hbase.composite.key.factory"="org.apache.hadoop.hive.hbase.SampleHBaseKeyFactory2");
“ hbase.composite.key.factory”应该是实现HBaseKeyFactory的类的标准类名。请参见SampleHBaseKeyFactory2,以获取同一包中的固定长度示例。该类必须在您的 Classpath 中,才能使以上示例正常工作。待办事项:将它们放置在容易接近的地方;他们目前仅在测试代码中。
HBase 列中存储的 Avro 数据
Note
自 Hive 0.14.0 起HIVE-6147
Hive 0.14.0 及更高版本支持通过将 Hro 列显示为 Hive 的结构来在 HBase 列中存储和查询 Avro 对象。这使 Hive 可以对可以深度构建的 HBase 数据执行临时分析。在 0.14.0 之前,HBase Hive 集成仅支持查询列中的原始数据类型。
示例 HiveQL 语句,其中test_col_fam
是列族,而test_col
是列名:
CREATE EXTERNAL TABLE test_hbase_avro
ROW FORMAT SERDE 'org.apache.hadoop.hive.hbase.HBaseSerDe'
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
"hbase.columns.mapping" = ":key,test_col_fam:test_col",
"test_col_fam.test_col.serialization.type" = "avro",
"test_col_fam.test_col.avro.schema.url" = "hdfs://testcluster/tmp/schema.avsc")
TBLPROPERTIES (
"hbase.table.name" = "hbase_avro_table",
"hbase.mapred.output.outputtable" = "hbase_avro_table",
"hbase.struct.autogenerate"="true");
要注意的重要属性是以下三个:
"test_col_fam.test_col.serialization.type" = "avro"
此属性告诉 Hive,给定列族下的给定列是 Avro 列,因此 Hive 需要对其进行反序列化。
"test_col_fam.test_col.avro.schema.url" = "hdfs://testcluster/tmp/schema.avsc"
使用此属性,您可以为将用于反序列化的列指定阅读器架构的位置。可以在此处提到的 HDFS 上使用,也可以使用"test_col_fam.test_col.avro.schema.literal"
属性内联提供。如果您有一个用于存储此架构的自定义存储,则可以编写AvroSchemaRetriever的自定义实现,并使用"test_col_fam.test_col.avro.schema.retriever"
等属性使用"avro.schema.retriever property"
将其插入。您需要确保具有此自定义类的 jar 在 HiveClasspath 上。有关用法的讨论以及指向其他资源的链接,请参见HIVE-6147。
"hbase.struct.autogenerate" = "true"
通过指定此属性,Hive 可以使用提供的模式自动推断列和类型。这样,您就可以避免为 Avro 模式手动创建列和类型,这些列和类型可能很复杂并且嵌套很深。
Put Timestamps
Version information
从 Hive 0.9.0开始
如果使用 Hive 插入 HBase 表中,则会添加 HBase 默认时间戳,通常是当前时间戳。可以使用SERDEPROPERTIES
选项hbase.put.timestamp
(必须是有效的时间戳记或-1
)在每个表的基础上重写,以重新启用默认策略。
Key Uniqueness
HBase 表和 Hive 表之间的细微差别是 HBase 表具有唯一键,而 Hive 表则没有。将具有相同键的多行插入到 HBase 中时,只会存储其中的一行(选择是任意的,因此不要依赖 HBase 来选择正确的行)。与之相反,Hive 乐于存储具有相同键和不同值的多行。
例如,pokes 表包含具有重复键的行。如果将其复制到另一个 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;
Overwrite
HBase 表和其他 Hive 表之间要注意的另一个区别是,使用 INSERT OVERWRITE 时,不会从表中删除现有行。但是,如果现有行具有与新行匹配的键,则会被覆盖。
Potential Followups
Hive/HBase 集成在许多领域肯定可以使用更多的爱:
更灵活的列 Map(HIVE-806,HIVE-1245)
如果没有给出 Map 说明,则使用默认列 Map
过滤器下推和索引编制(请参阅FilterPushdownDev和IndexDev)
公开 timestamp 属性,可能还支持将其视为分区键
允许每表 hbase.master 配置
运行事件探查器并使列 Map 中的每行开销最小化
用户定义的例程,用于通过 HBaseClient 端 API(HIVE-758 和 HIVE-791)进行查找和数据加载
日志记录非常嘈杂,有很多虚 Pseudoexception。调查这些并解决其原因或抑制它们
Build
存储处理程序的代码位于hive/trunk/hbase-handler
下。
HBase 和 Zookeeper 依赖关系是通过 ivy 获取的。
Tests
hbase-handler/src/test/org/apache/hadoop/hive/hbase
下提供了类单元测试。
积极的 QL 测试在hbase-handler/src/test/queries
下。它们使用 HBase Zookeeper 微型集群在过程中托管灯具表,因此无需独立安装 HBase 即可运行它们。为避免端口冲突导致的故障,请勿尝试在运行实际 HBase 主服务器或 Zookeeper 的同一台计算机上运行这些测试。
可以通过 ant 这样执行 ant 来执行 QL 测试:
ant test -Dtestcase=TestHBaseCliDriver -Dqfile=hbase_queries.q
Eclipse 启动模板仍有待定义。
Links
有关如何将数据从 Hive 批量加载到 HBase 的信息,请参见HBaseBulkLoad。
有关在 HBase 顶部添加类似 SQL 的查询语言支持的另一个项目,请参见HBQL(与 Hive 不相关)。
Acknowledgements
- 此功能的主要贡献者是 Samuel Guo,他在补丁的早期草案中完成了大部分开发工作
未解决问题(JIRA)
||
||
|T|Key|Summary|Assignee|Reporter|P|Status|Resolution|Created|Updated|Due|
Loading...