hive存储处理器(StorageHandlers)以及hive与hbase整合
此篇文章基于hive官方英文文档翻译,有些不好理解的地方加入了我个人的理解,官方的英文地址为:
1.https://cwiki.apache.org/confluence/display/Hive/StorageHandlers
2.https://cwiki.apache.org/confluence/display/Hive/HBaseIntegration
一 存储处理器介绍
通过HIVE存储处理器,不但可以让hive基于hbase实现,还可以支持cassandra
JDBC MongoDB 以及 Google
Spreadsheets
HIVE存储器的实现原理基于HIVE以及Hadoop的可扩展性实现:
输入格式化(input formats)
输出格式化(output formats)
序列化/反序列化包(serialization/deserialization
librarises)
除了依据以上可扩展性,存储处理器还需要实现新的元数据钩子接口,这个接口允许使用HIVE的DDL语句来定义和管理hive自己的元数据以及其它系统的目录(此目录个人理解为其它系统的元数据目录)
一些术语:
HIVE本身有的概念:
被管理的表即内部表(managed):元数据由hive管理,并且数据也存储在hive的体系里面
外部表(external table):表的定义被外部的元数据目录所管理,数据也存储在外部系统中
hive存储处理器的概念:
本地(native)表:hive不需要借助存储处理器就可以直接管理和访问的表
非本地(non-native)表:需要通过存储处理器才能管理和访问的表
内部表 外部表 和 本地表 非本地表 形成交叉,就有了下面四种形式的概念定义:
被管理的本地表(managed native):通过CREATE TABLE创建的表
外部本地表(external native):通过CREATE EXTERNAL
TABLE创建,但是没有带STORED BY子句
被管理的非本地表()managed non-native):通过CREATE TABLE 创建,同时有STORED
BY子句,hive在元数据中存储表定义,但是不创建任何文件(我的理解是存放数据的目录文件,hive在定义好表结构后会创建对应的目录来存储对应的数据),hive存储处理器向存储数据的系统发出一个请求来创建一个一致的对象结构;
外部非本地(external non-native):通过CREATE EXTERNAL
TABLE创建,并且带有STORED BY子句;hive在自己的元数据中注册表的定义信息,并且通过调用存储处理器来检查这些注册在hive中的信息是否与其它系统中原来定义的信息一致
通过hive创建表结构的DDL语句:
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [col_comment], col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name, ...)] INTO num_buckets BUCKETS]
[
[ROW FORMAT row_format] [STORED AS file_format]
| STORED BY 'storage.handler.class.name' [WITH SERDEPROPERTIES (...)]
]
[LOCATION hdfs_path]
[AS select_statement]
具体的使用样例,会在下面详细说明
二 Hive与Hbase的整合
hive和Hbase的整合通过Hbase
handler jar包实现,它的形式为hive-hbase-x.y.z.jar ,这个处理器需要依赖hadoop0.20以上版本,并且只在hadoop-0.20.x
hbase-0.92.0 和zookeeper-3.3.4 上进行过测试。如果hbase版本不是0.92则需要基于你使用的版本重新编译对应的hive存储处理器。
为了创建一张可以被hive管理的hbase的表,需要在hive的ddl语句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.table.name属性是可选的,用它来指定此表在hbase中的名字,这就是说,允许同一个表在hive和hbase中有不同的名字。上述语句中,在hive中的表名叫hbase_talbe_1,在hbase中,此表名叫xyz。如果不指定,两个名字则会是相同的。
当执行完命令后,就可以在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
上面的输出中没有列val的信息,虽然在建表语句中已经指定了这个列名。这是因为在hbase中只有列族的名字才会被定义在表级的元数据中,列族中的列只定义在行级别的元数据中。
下面的语句是定义怎么把数据从hive中加载进入HBase的表,表pokes是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
Inserting large amounts of data may be slow due to WAL overhead; if you would like to disable this, make sure you have HIVE-1383 (as of Hive 0.6), and then issue this command before the INSERT:
set hive.hbase.wal.enabled=false;
Warning: disabling WAL may lead to data loss if an HBase failure occurs, so only use this if you have some other recovery strategy available.
如果想基于已经存在的hbase表创建hive可访问的表,则需要用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表的列族以及列的定义信息。
hive与hbase的列匹配
有两种SERDEPROPERTIES配置信息来控制HBase列到HIve的映射
1.hbase.columns,mapping
2.hbase.table.default.storage.type
这个属性可以有String和二进制两种类型的值,默认是String;这个选项只有在hive0.9这个版本可用, 并且在早期的版本中,只有String类型可用
当前列匹配使用起来显得有点笨重和憋手:
1.每个hive的列,都需要在参数hbase.columns.mapping中指定一个对应的条目(比如:a:b或者:key就叫一个条目),多个列之间的条目通过逗号分隔;也就是说,如果某个表有n个列,则参数hbase.columns.mapping的值中就有n个以逗号分隔的条目。比如:
"hbase.columns.mapping" = ":key,a:b,a:c,d:e" 代表有两个列族,一个是a一个是d,a列族中有两列,分别为b和c
注意,hbase.columns.mapping的值中是不允许出现空格的
2.每个匹配条目的形式必须是:key或者列族名:[列名][#(binary|string)](前面带有#标识的是在hive0.9才添加的,早期的版本把所有都当作String类型)
1)如果没有给列或者列族指定类型,hbase.table.default.storage.type的值会被当作这些列或者列族的类 型
2)表示类型的值(binary|string)的任何前缀都可以被用来表示这个类型,比如#b就代表了#binary
3)如果指定列的类型为二进制(binary)字节,则在HBase的单元格的存储类型也必须为二进制字节
3.必须窜至一个:key的形式匹配条目(不支持复合key的形式)
4.在hive0.6版本以前,是通过第一个条目来作为关键字(key)字段,从0.6以后,都需要直接通过:key的方式来指定
5.当前没有办法可以访问到HBase的时间撮属性,并且查询总是访问到最新的数据(这条主要是因为hbase单元格数据存储是有版本的,根据时间撮)
6. 因为HBase的列定义没有包含有数据类型信息,所以在存储的时候,会把所有的其它类型都转换为string 代表;所以,列数据类型不支持自定义
7. 没有必要对HBase的所有列族都进行映射,但是没有被映射的列族不能通过访问Hive表读取到数据;可以把多个Hive表映射到同一个HBase的表
下面的章节提供更加详细的例子,来说明当前各种不同的列映射
多个列和列族
下面的例子包含三个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"
);
INSERT OVERWRITE TABLE hbase_table_1 SELECT foo, bar, foo+1, foo+2
FROM pokes WHERE foo=98 OR foo=100;
上面的例子中,hive拥有除去可以外的列为三个,value1
value2 value3,对应的HBase表为两个列族,分别为a和d,其中a包括两列(b和c);值的对应关系从左到右一一对应,a列族中的b列对应value1,c列对应value2,d列族的e列对应value3
下面是从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数据类型与Hbase列族的映射例子。每行都可以包含不同的列组合,列名与map的可以对应,values与列值对应。
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;
其中cf表示列族,冒号后面为空,它与Hive表的列value对应,即value的key为cf列族的列,可以通过下面HBase的查询来理解key为列名,value为值的用法。
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
cf为列族名,val_100为hive表中MAP(集合)的key,100为MAP(集合)中的val_100的值
下面是对应的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类型,否则会失败,因为key是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>)
注意:当hbase.columns.mapping中有“:key,cf:”这样的值,即列族冒号后面为空时,表示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.columns.mapping中值类型用法列举
如果没有指定值的类型,比如cf:val,则采用配置hbase.table.default.storage.type的值为数据类型
1.当不配置hbase.table.default.storage.type时,它默认是string,如果有二进制的数据类型,则如下定义:
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"
);
2.如果显示的指定hbase.table.default.storage.type为binary时,如果类型有string类型,则需要指定,如:
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"
);
cf:val#s 中的#s就表示类型为string,cf:foo没有配置类型,则采用hbase.table.default.storage.type的配置,为binary
添加时间戳
当用hive给HBase的表添加记录时,时间戳默认为当前时间,如果想改变这个值,可以通过设置SERDEPROPERIES属性的可选配置项hbase.put.timestamp,当这个配置项为-1的时候,就是默认策略,即添加记录为当前时间戳
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"
"hbase.put.timestamp" = "2013-03-17 09:04:30"
)
主键唯一性
HBase与Hive的表有一个细微的差别,就是HBase的表有一个主键,并且需要唯一,但是Hive没有;如果不能保证这个主键的唯一,则HBase存储的时候,只能存储其中一个,这会导致查询的时候,hive总能找到正确的值,而HBase出来的结果就不确定
如下,在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)
当执行OVERWRITE时,HBase中已经存在的记录是不会被删除的;但是,如果存在的记录与新纪录的主键(key)是一样的,则老数据会被覆盖
hive存储处理器(StorageHandlers)以及hive与hbase整合的更多相关文章
- Hive和HBase整合用户指南
本文讲解的Hive和HBase整合意思是使用Hive读取Hbase中的数据.我们可以使用HQL语句在HBase表上进行查询.插入操作:甚至是进行Join和Union等复杂查询.此功能是从Hive 0. ...
- Hadoop Hive与Hbase整合+thrift
Hadoop Hive与Hbase整合+thrift 1. 简介 Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的sql查询功能,可以将sql语句 ...
- 大数据工具篇之Hive与HBase整合完整教程
大数据工具篇之Hive与HBase整合完整教程 一.引言 最近的一次培训,用户特意提到Hadoop环境下HDFS中存储的文件如何才能导入到HBase,关于这部分基于HBase Java API的写入方 ...
- Hive篇---Hive与Hbase整合
一.前述 Hive会经常和Hbase结合使用,把Hbase作为Hive的存储路径,所以Hive整合Hbase尤其重要. 二.具体步骤 hive和hbase同步https://cwiki.apache ...
- HBase(六)HBase整合Hive,数据的备份与MR操作HBase
一.数据的备份与恢复 1. 备份 停止 HBase 服务后,使用 distcp 命令运行 MapReduce 任务进行备份,将数据备份到另一个地方,可以是同一个集群,也可以是专用的备份集群. 即,把数 ...
- Hive(五):hive与hbase整合
配置 hive 与 hbase 整合的目的是利用 HQL 语法实现对 hbase 数据库的增删改查操作,基本原理就是利用两者本身对外的API接口互相进行通信,两者通信主要是依靠hive_hbase-h ...
- 《OD大数据实战》HBase整合MapReduce和Hive
一.HBase整合MapReduce环境搭建 1. 搭建步骤1)在etc/hadoop目录中创建hbase-site.xml的软连接.在真正的集群环境中的时候,hadoop运行mapreduce会通过 ...
- Hive与Hbase整合
Hive与Hbase整合 1.文档 Hive HBase Integration 2.拷贝jar文件 2.1.把Hbase的lib目录下面的jar文件全部拷贝到Hive的lib目录下面 cd /hom ...
- Apache Hive 存储方式、压缩格式
简介: Apache hive 存储方式跟压缩格式! 1.Text File hive> create external table tab_textfile ( host string com ...
随机推荐
- New Concept English three (51)
22 76 Predicting the future is notoriously difficult. Who could have imagined, in the mid 1970s, for ...
- CERC2016 爵士之旅 Jazz Journey
传送门(洛谷) 题目大意 给定$n$个位置,和一个长为$m$的序列$A$,你需要经过一条直接的边从第$A_i$个位置到第$A_{i+1}$个位置. 每条有向边$(u,v)$分为两种,第一种可以花费$C ...
- swing之记事本的简单实现
package gui1; import java.awt.BorderLayout; import javax.swing.ImageIcon; import javax.swing.JButton ...
- Android UI--提高Android UI体验
1,自定义虚拟键盘 当一个用户被要求在一个文本框输入时希望又怎样的体验? 从用户需求来看,虚拟键盘应该改变以帮助用户输入的数据.这里是一些例子: 如果一个视图是一个电子邮件地址,一个键盘的“@”符号 ...
- IntellJ IDEA快捷键汇总
今天开始使用IDEA,各种不习惯,一会Eclipse一会IDEA来回切换,需要一个熟悉的过程,记录一下常用的快捷键. IDEA常用快捷键 Alt+回车 导入包,自动修正Ctrl+N 查找类Ctrl+ ...
- SQL Sever 学习系列之三
SQL Sever 学习系列之三 SQL Server 学习系列之一(薪酬方案+基础) SQL Server 学习系列之二(日期格式问题) 五.经理今天刚谈到with的用法(with的 ...
- 关于jsp和html页面中的三种弹出框
代码: <!-- 引入jquery 由于在下面使用jquery选择器,与弹出框无关 --> <script type="text/javascript" src= ...
- Python中获得当前目录和上级目录
[转]原文地址:http://blog.csdn.net/liuweiyuxiang/article/details/71154346 获取当前文件的路径: from os import path d ...
- JavaScript语言基础-包装对象
- jdbcTemplate学习(二)
前面讲了增加.删除.更新操作,这节讲一下查询. 查询操作: (一)查询一个值(不需要注入参数) queryForObject(String sql, Class<T> requiredTy ...