一、Hive简介
hive的设计就是让精通SQL技能但对编写传统MapReduce程序生疏的分析师,也能对hdfs中存储的大规模数据集运行查询。但是SQL并不适合开发复杂的机器学习算法,但对很多分析任务非常有用。
hive把SQL查询转换为一系列的在Hadoop集群上运行的MapReduce作业。
Hive把数据组织为表,将数据存储到HDFS中,并把元数据存储到名为metastore的数据库中。
Metastore默认运行在本地服务器上,此时hive表的定义存储在本地机器上,因此无法和其他用户共享这些定义。Hive的元数据也可以存储到关系型数据库中,这时hive就可以和其它用户共享这些定义。而且在后期开发中,我们还会接触到hcatelog组件,通过该组件我们能够实现hive与pig、MapReduce、stream开发过程中的元数据共享。
二、hive配置方式
1、全局级别配置:Hive的配置文件为---hive-site.xml,他在hive的conf目录下。这个目录中还包括hive-default.xml,记录着hive运行的选项和默认值。并且还可以通过两种方式,指定hive-site.xml配置文件的位置,分别是:①通过-config选项给hive重新定义hive查找hive-site.xml文件的目录:hive –config /usr/tom/dev/hive-conf;②也可以设置HIVE_CONF_DIR环境变量来指定配置文件目录。注意,这个是指定包含配置文件的目录,而不是配置文件hive-site.xml本身。
2、会话级别配置:Hive还允许通过hive指令为单个会话设置属性:hive –hiveconf ds.default.name=localhost –hiveconf mapred.job.tracker=localhost:8021。
3、会话内局部配置:Hive还可以在一个会话中使用set指令更改设置,这对于某个特定的查询修改hive或者mapReduce作业非常有用:hive> SET hive.enforce.bucketing=true
注意:Hive的设置属性有一个优先层次,如下:①hive set 命令;②命令行-hiveconf选项;③hive-site.xml;④hive-default.xml;⑤hadoop-site.xml;⑥hadoop-default.xml;
4、hive日志配置
通过对hive日志的配置,主要用来指定日志的输出级别和其他日志的相关设置。并且Hive的错误日志保存在【本地文件系统/tmp/$USER/hive.log中】。日志具体的配置方式如下:
①通过配置文件对日志配置,配置文件路径为:conf/hive-log4j.properties
②通过hive会话对日志配置,例如:hive –hiveconf hive.root.logger=DEBUG,console
三、hive服务简介
hive能够提供一系列服务,可通过hive命令指定运行那项服务。在运行hive命令时通过-service选项指定使用哪项服务。还可以键入hive –service help查看hive可用服务列表。默认情况下启动hive外壳环境(即cli服务)。下面分别介绍一下hive的服务:
1、cli:hive的命令行接口(外壳环境)。这是默认的服务。
2、hiveserver:让hive可以提供Thrift服务的服务器形式运行,允许用不同语言编写的客户端进行访问。使用Thrift、JDBC和ODBC连接器的客户端需要运行hive服务器来和hive进行通讯。通过设置HIVE_PORT环境变量来指明服务器所监听的端口号(默认为10 000)
3、hwi:hive的web接口。
4、jar:与hadoopjar等价的hive的接口。这是运行类路径中同时包含hadoop和hive类的java应用程序的便捷方法。
5、metastore:默认情况下,metastore和hive服务运行在同一个进程里。使用这个服务,可以让metastore作为一个单独的进程运行。通过设置METASTORE_PORT环境变量可以指定服务器监听的端口号。
四、hive交互方式
1、hive外壳环境(cli):
是我们和hive进行交互、发出hiveQL命令的主要方式。在启动hive客户端的时候,默认就是启动该服务。进入hive外壳环境的方式是,直接键入hive指令即可。
2、非交互模式运行hive外壳:
①使用-f选项可以运行指定文件中的指令:hive –f script.q
②对于短脚本可使用-e选项运行命令:hive –e ‘select * from test’;
3、编写相应程序与hive服务器交互:
如果以服务器方式运行hive(hive –service hiveserver),就可以编写多种程序以不同机制连接到服务器。hive客户端与服务之间的联系如下:
① Thrift客户端:简化了在多种编程语言中运行hive命令。Hive的thrift绑定支持C++、java、php、python和ruby。并且可以在hive安装目录的hive/lib下找到对应语言的Thrift绑定
②JDBC驱动:hive提供了纯java的jdbc驱动,在以jdbc:hive://host:port/dbname形式配置JDBCURI以后,java应用程序就可以在指定的主机和端口连接到在另一个进程中运行的hive服务器。
③ODBC驱动:hive的ODBC驱动允许支持ODBC协议的应用程序连接到hive。
4、hadoop监控管理页面交互
在该模式下就是采用hive web interface与hive服务进行交互的。指令执行过程与hive cli下非常相似。
五、Metastore详解
Metastore是hive元数据的集中存放地,metastore包括两部分:服务和后台数据的存储。当前metastore支持多种形式,分别为:内嵌metastore、本地metastore、远程metastore。默认情况下是内嵌metastore。
1、内嵌metastore:meatstore服务和hive服务运行在同一个JVM中,包含一个内嵌的以本地磁盘作为存储的Derby数据库实例。内嵌metastore只使用一个内嵌derby数据库每次只能访问一个磁盘上的数据库文件,因此一次只能为每个metastore打开一个hive会话。如果开启第二个会话,当需要连接metastore时,就会报错。
2、本地metastore:Metastore服务仍然和hive服务运行在同一台机器上或在远程机器上,但是不在使用内嵌derby数据库,而是使用一个独立的数据库,能够支持多回话。并且任何JDBC兼容的数据库都可以通过设置供metastore使用。常用的是mysql数据库。
3、远程metastore:一个或多个metastore服务器和hive服务运行在不同的进程内,这样一来,数据库层可以完全配置于防火墙后,客户端则不需要数据库凭证(用户名和密码),从而提供更好的可管理性和安全。通过把hive.metastore.local设置为false,hive.metastore.uris设为metastore服务器URI,来把hive服务设置为远程metastore。
六、hive与传统数据库进行比较
hive在很多方面和传统数据库类似,但是它底层对HDFS和MapReduce的依赖意味着它的体系结构有别于传统数据库。
1、读时模式vs写时模式
传统数据库:表的模式是在数据加载时强制确定的。如果加载数据时发现数据不符合模式,则拒绝加载数据。因为数据在写入数据库时对照模式进行检查。称为“写时模式”;
Hive数据仓储:hive对数据的验证并不在加载数据时进行,而在查询时进行。称为“读时模式”;
2、更新、事务和索引
Hive不支持这些特性,hive被设计用MapReduce操作HDFS数据,采用“全表扫描”的操作,而表更新则是通过把数据变换后放入新表实现的。
Hbase和HDFS相比,有着不同的存储特性,例如更新和列索引,因此希望hive可以利用这些hbase的特性。Hbase和hive的集成还处于早期的开发阶段。
七、hive表介绍
CREATE [EXTERNAL] TABLE [IF NOT EXITSTS] table_name
(col_name data_type,…)
[PARTITIONED BY (col_name data_type,…)]
[CLUSTERED BY (col_name,col_name,…)]
[SORTED BY (col_name,col_name,..)]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[AS select_statement]
1、hive表的组成:Hive表格逻辑上有存储在HDFS上的数据和存储在关系型数据库中的元数据组成。
2、EXTERNAL:Hive中的表分为两大类型---托管表和外部表。默认Hive采用托管表,即hive把数据移入“仓储目录(/usr/hive/warehouse/..)”,并在删除该表时元数据和数据都会被删除;而外部表就是让hive到仓储目录以外的位置访问数据,删除时只会删除掉元数据。使用EXTERNAL关键字后,hive就知道创建外部表。
注意:加载操作只是文件系统的文件移动,因此它的执行速度很快,但是即使是托管表,hive也并不会检查表目录中的文件是否符合为表所声明的模式,如有数据和模式不匹配,只有在查询时才会知道。
使用法则:如果所有处理都有Hive完成,应该使用托管表;但如果要用hive和其他工具来处理同一个数据集,应该使用外部表。普遍的用法是把存放在hdfs的原始数据集用作外部表使用,然后用hive的切换功能把数据移到托管的hive表。
3、data_type:hive支持原子和复杂数据类型,原子数据类型包括数值型、布尔型、字符串类型;复杂数据类型包括数组、映射和结构。
基本数据类型:tinyint—1个字节;smallint—2个字节;int—4个字节;bigint—8个字节;
Float—4个字节;double—8个字节;boolean—true/false;string—字符串。
复杂数据类型:Array—一组有序字段,字段的类型必须相同;Map—一组无序的键/值对。键的类型必须是原子的;值可以是任何类型,但同一个映射的键类型必须相同,值的类型也必须相同;Struct—一组命名的字段,字段类型可以不同。复杂数据类型允许任意层次的嵌套,但是复杂数据类型声明必须使用尖括号指明其中的数据字段类型。
注:Hive只提供了一种存储文本的数据类型String,该类型是一个变长字符串,理论上最大可以存储2G字符数,但是存储那么大的值,效率会很低。Sqoop提供了大对象的支持。
类型转换:①任何数据类型都能隐式转换为一个范围更广的类型。②采用cast操作显示进行数据类型转换。
4、PARTITIONED BY:Hive可以对表进行分区,根据“分区列”的值对表进行策略划分的机制。使用分区可以加快数据分片的查询速度。一个表可以以多个维度进行分区。
注:如果在创建表时使用分区,则在加载数据时,需要指定把数据加载到指定分区中。
5、CLUSTERED BY:hive可以对表或分区进一步分为“桶”。理由有2,第一个可获得更高的查询处理效率,例如连接两个在相同列上划分了桶的表,可以使用map端连接高效实现;第二个是取样更高效。(例如:create table user(id int,name string) CLUSTERED BY(id) INTO 4 BUCKETS)。
注:每个桶就是表目录里的一个文件,分桶的常用方式是把分桶字段进行hash处理,所得的哈希值除以桶数,将数据分布到对应的桶中。
6、ROW FORMAT和STORED AS:在创建hive表时,如果没有用这连个子句,那么hive所使用的默认格式分割文本,每行(line)存储一个数据行(row)。
默认的各行间的分隔符是换行符(\n);
默认的行内分隔符不是制表符,而是ASCII控制码集合中的Control-A(它的ASCII码为1);
默认的集合元素分隔符是字符Control-B,它用于分割ARRAY和STRUCT的元素或MAP的键值对;
默认的映射建(map key)分隔符是Control-C,它用于分割MAP的键和值。
默认情况下的建表语句为:
create table ….
Row format delimited
Fields terminared by ‘\001’
Collection items terminated by ‘\002’
map keys terminated by ‘\003’
lines teminated by ‘\n’
stored as textfile;
注意:hive表中的数据存储在hdfs中,而且hdfs只支持utf8编码格式,所以我们在处理中文的过程中,最好将中文处理为utf8格式编码进行存储,查看起来也特别方便。
八、HQL简介
1、常用database操作指令:
① 查看表空间:show databases;
② 选择对应的表空间:use database_name;
③ 创建表空间:create database database_ame;
④删除表空间:这个比较复杂,如果要直接删除表空间下面的数据,执行:dfs –rm –r /user/hive/warehouse/database_name就可以;但是如果要删除元数据中database的定义,则首先需要删除database中的table,然后再执行drop database database_name才可以,否则会抛出异常。
2、常用table操作指令:
① 查看已有的表:show tables;
② 创建表:请查看第七部分hive表的介绍。
③ 查看表的字段信息:desc table_name;
④ 查看表的create语句:show create table table_name;
⑤ 查看分区:show partitions table_name;
3、表的常用操作:
① 加载数据:LOAD DATA [LOCAL] INPATH ‘/mfs/logs/warehouse/项目名/业务名/数据文件’ [OVERWRITE] INTO TABLE test;
这个操作是把本地文件加载到hive仓储目录中,但是并不解析文件或把文件存储为内部数据库格式。在hive中仓储目录(warehouse directory)是由选项hive.metastore.warehouse.dir控制,默认为/user/hive/warehouse.
LOCAL关键字:是加载本地文件到hive仓储中,即加载文件到hdfs中;如果没有该关键字,hive则认为把hdfs中已经存在的文件加载到hive对应的仓储目录中
OVERWRITE关键字:告诉hive删除表中对应目录中已有的所有文件;如果省去该关键字,hive就简单的把新的文件加入目录(除非目录下正好有同名的文件,否则将替换掉原有的同名文件)
② Insert overwrite table---表明目标表内的内容会被替换掉
③多表插入:from table_name insert overwrite table table_name1…. Insert overwrite table table_name2….
④Hive查询:SELECT year,MAX(temperature)
FROM test
WHERE temperature != 9999
AND (quality = 0 OR quality = 1 OR quality = 4)
GROUP BY year;
注意:order by能够产生完全排序的结构,但是它通常只是一个reducer来做到的,所以对于大规模的数据集,效率非常低。很多情况下,并不需要结果是全局排序的,此时可以用hive的非标准扩展sort by,sort by 为每个reducer产生一个排序文件。
4、表的修改
①重命名表:alter table table_name1 rename to table_name2;
②添加新的列:alter table table_name add columns(col1 string);
5、删除表
① 删除表:drop table table_name1(外表只删除元数据)
② 只删除表的数据:dfs –rmr /usr/hive/warehouse/table_name1;
6、使用MapReduce脚本
使用hadoop streaming,transform,map,reduce子句这样的方法,便可以在hive中调用外部脚本。例如:add file /*.py;from table_name1 select transform(year,temperature,quality) using ‘*.py’ as year,temperature;
7、连接
①内连接:select table_name1.*,table_name2.* from table_name1 join table_name2 on(table_name1.col1 = table_name2.col3)
②查看连接中MapReduce作业实现:EXPLAIN select …. From …join ….on();
③外连接:select sales.*,things.* from sales left outer join things on (sales.id = things.id)
注:hive还支持右链接和全连接。
④半连接:由于hive不支持in子查询,但可以用left semi join来达到同样的效果—select * from things left semi join sales on(sales.id=things.id)等价于select * from things where things.id in (select id from sales).
注:left semi join 查询时必须遵循一个限制:右表(sales)只能在on子句中出现。
⑤Map连接:如果有一个连接表小到足以放入内存,hive就可以把较小的表放入每个mapper的内存来执行连接操作。如果要指定使用map连接,需要在sql中使用c语言风格的注释:select /*+ mapjoin(things)*/ sales.*,things.* from sales join things on (sales.id=things.id)
注:执行这个查询不使用reducer,因此这个查询对right或full outer join无效。
⑥子查询:hive对子查询支持有限,它只允许子查询出现在select语句的from子句中。
8、视图
在hive中,创建视图时并不把视图“物化”存储到磁盘上。相反,视图的select语句只是在执行引用视图的语句时才执行。
九、访问hiveserver实例
在hiveserver中,当前已经出现两个版本,分别是hiveserver和hiveserver2.其中hiveserver2新增加了权限管理和多进程进行。针对这两个版本,他们对应的客户端client程序不在相同,需要注意。
1、hiveserver python client实例:
#!/usr/bin/python2.7
#hive --service hiveserver >/dev/null 2>/dev/null&
#/usr/lib/hive/lib/py
import sys
from hive_service import ThriftHive
from hive_service.ttypes import HiveServerException
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
def hiveExe(sql):
try:
transport = TSocket.TSocket('10.6.219.214', 10000)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = ThriftHive.Client(protocol)
transport.open()
client.execute(sql)
print"The return value is : "
print client.fetchAll()
print"............"
transport.close()
except Thrift.TException, tx:
print'%s' % (tx.message)
if __name__ == '__main__':
#alter table startevent add if not exists partition(dateline=20131231)
hiveExe("select * from yidong.startevent")
2、 hiveserver2 python client 实例
#!/usr/bin/python2.7
#hive --service hiveserver2 >/dev/null 2>/dev/null&
#install pyhs2,first install cyrus-sasl-devel,gcc,libxml2-devel,libxslt-devel
#hiveserver2 is different from hiveserver on authority
import pyhs2
conn = pyhs2.connect(host='10.6.219.215',port=10000,authMechanism="PLAIN", user='hive', password='', database='yidong')
cur = conn.cursor()
cur.execute("select * from startevent limit 10")
for i in cur.fetch():
print i
cur.close()
conn.close()