第5章Hive数据仓库
5.1Hive概述
5.1.1Hive简介

Hive起源于Facebook公司,Facebook公司有大量的日志数据,而Hadoop是实现了MapReduce模式开源的分布式并行计算的框架,可轻松处理大规模数据。而对于Java语言熟悉的工程师来说开发MapReduce程序很容易,但对于其他语言使用者则难度较大。因此,Facebook开发团队想设计一种使用SQL对日志数据查询分析的工具,Hive就诞生于此。只要懂SQL,就能够利用Hive胜任大数据分析方面的工作,节省了开发人员的学习成本。
Hive是建立在Hadoop文件系统上的数据仓库分析系统,它提供了一系列工具,能够对存储在HDFS中的数据进行数据提取、转换和加载,可以存储、查询和分析存储在Hadoop中的大规模数据。Hive定义简单的类SQL(即HQL),可以将结构化的数据文件映射为一张数据表,允许熟悉SQL的用户查询数据。 
Hive采用了SQL的查询语言HQL,因此很容易将Hive理解为数据库。从结构上来看,Hive和数据库除了拥有类似的查询语言外,再无类似之处,Hive与MySQL对比如表51所示。


表51Hive 与MySQL对比



对比项HiveMySQL

查询语言HQLSQL
数据存储位置HDFS块设备、本地文件系统
数据格式用户定义系统决定
续表


对比项HiveMySQL

数据更新不支持支持
事务不支持支持
执行延迟高低
可扩展性高低
数据规模大小

5.1.2Hive的架构
Hive的架构如图51所示。


图51Hive的架构







(1) 用户接口: 主要包括CLI、JDBC/ODBC客户端和Web接口。其中,CLI为Shell命令行; JDBC/ODBC是Hive的Java接口实现,与传统数据库JDBC类似; Web接口通过浏览器访问Hive。
(2) 元数据库: Hive 将元数据存储在数据库中(MySQL或者Derby)。Hive中的元数据包括表的名字、表的列和分区及其属性、表的属性(是否为外部表等)、表的数据所在目录等。
(3) Thrift服务器: 允许客户端使用包括Java或其他很多种语言,通过编程的方式远程访问Hive。
(4) 解释器、编译器、优化器、执行器: 完成 HQL 查询语句从词法分析、语法分析、编译、优化以及查询计划的生成。生成的查询计划存储在HDFS 中,并在随后调用执行MapReduce。
5.1.3Hive的优缺点
1. Hive的优点

(1) 适合大数据的批量处理,解决了传统关系数据库在大数据处理上的瓶颈。
(2) Hive构建在Hadoop之上,充分利用了集群的存储资源、计算资源,最终实现并行计算。
(3) Hive学习使用成本低。Hive支持标准的SQL语法,免去了编写MapReduce程序的过程,减少了开发成本。
(4) 具有良好的扩展性,且能够实现和其他组件的结合使用。
2. Hive的缺点
(1) HQL的表达能力依然有限。由于本身SQL 的不足,不支持迭代计算,有些复杂的运算用HQL不易表达,还需要单独编写MapReduce来实现。
(2) Hive的运行效率低、延迟高。Hive是转换成MapReduce任务来进行数据分析,MapReduce是离线计算,所以Hive的运行效率也很低,而且是高延迟。
(3) Hive调优比较困难。由于Hive是构建在Hadoop之上的,Hive的调优还要考虑MapReduce层面,因此Hive的整体调优比较困难。
5.2Hive的安装
5.2.1安装MySQL

(1) 下载MySQL的yum源,在 CentOS命令行中输入如下命令: 

wget http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm

(2) 查看下载源中包含的rpm包,在CentOS命令行中输入如下命令: 

rpm -qpl mysql57-community-release-el7-7.noarch.rpm

(3) 安装MySQL,在CentOS 命令行中输入如下命令: 

yum install -y mysql-community-server

(4) 启动mysqld服务,在CentOS 命令行中输入如下命令: 

systemctl start mysqld.service

(5) 查找MySQL初始密码,在CentOS 命令行中输入如下命令: 

grep "password"/var/log/mysqld.log

运行结果如下所示:




(6) 登录MySQL,在CentOS命令行中输入mysql uroot p,输入第(5)步查找的初始密码。




(7) 设置安全级别,MySQL命令如下: 

set global validate_password_policy=0;

(8) 设置密码长度,MySQL命令如下: 

set global validate_password_length=4;

(9) 设置密码,MySQL命令如下: 

set password=password('1234');

(10) 创建数据库,MySQL命令如下: 

create database hive;

运行结果如下所示: 




(11) 创建MySQL用户,名称为hadoop,设置用户密码,MySQL命令如下: 

grant all on *.* to hadoop@'%' identified by "hadoop";

grant all on *.* to hadoop@'localhost' identified by 'hadoop';

grant all on *.* to hadoop@'bigdata02' identified by 'hadoop';

flush privileges;

运行结果如下所示: 




5.2.2安装Hive
(1) 下载安装包,下载镜像为http://mirror.bit.edu.cn/apache/hive/hive2.3.7/apachehive2.3.7bin.tar.gz。
将安装包上传到服务器,并进行解压,其中hadoop是Hive的安装目录,命令如下: 

tar -zxvfapache-hive-2.3.7-bin.tar.gz-C /hadoop/

(2) 配置Hive环境变量,在etc/profile文件中加入环境变量,内容如下: 

export HIVE_HOME=/hadoop/apache-hive-2.3.7-bin/

export PATH=$HIVE_HOME/bin:$PATH

配置完成并保存后,刷新配置文件,执行命令source /etc/profile。
(3) 在Hadoop下创建hive文件夹,在CentOS命令行上执行以下Hadoop命令: 

hadoop fs -mkdir -p /hive/tmp

hadoop fs -mkdir -p /hive/warehouse

hadoop fs -chmod g+w /hive/tmp

hadoop fs -chmod g+w /hive/warehouse

hadoop fs -chmod -R 777 /user/hive/tmp

(4) 修改Hive配置文件,在CentOS命令行上执行以下命令: 

cd /hadoop/apache-hive-2.3.7-bin/etc

cp hive-env.sh.template hive-env.sh

cp hive-default.xml.template hive-site.xml

cp hive-log4j2.properties.template hive-log4j2.properties

cp hive-exec-log4j2.properties.template hive-exec-log4j2.properties

在hiveenv.sh文件中加入JAVA_HOME、HADOOP_HOME配置,内容如下:  

export JAVA_HOME=/usr/java/jdk1.8.0_161

export HADOOP_HOME=/hadoop/hadoop-2.7.7

在hivesite.xml文件中加入以下配置,注意XML文件中的ConnectionUserName和ConnectionPassword配置的是MySQL的用户名和密码。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<configuration>

<property>

<name>hive.exec.scratchdir</name>

<value>/hive/tmp</value>

</property>

<property>

<name>hive.metastore.warehouse.dir</name>

<value>/hive/warehouse</value>

</property>

<property>

<name>hive.querylog.location</name>

<value>/hive/log</value>

</property>

<!--配置MySQL数据库连接信息-->

<property>

<name>javax.jdo.option.ConnectionURL</name>

<value>jdbc:mysql://localhost:3306/metastore?createDatabaseIfNotExist=true&amp;characterEncoding=UTF-8&amp;useSSL=false</value>

</property>

<property>

<name>javax.jdo.option.ConnectionDriverName</name>

<value>com.mysql.jdbc.Driver</value>

</property>

<property>

<name>javax.jdo.option.ConnectionUserName</name>

<value>hadoop</value>

</property>

<property>

<name>javax.jdo.option.ConnectionPassword</name>

<value>hadoop</value>

</property>

</configuration>

(5) 初始化Hive,在 CentOS命令行上执行以下命令: 

./schematool -dbType mysql -initSchema hive hive

(6) 下载mysqlconnectorjava5.1.46.jar,并复制到Hive安装目录的lib目录下。
(7) 启动Hive,在CentOS命令行上执行命令hive,运行结果如下所示。




5.3Hive数据库相关操作
Hive是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行,通过自己的SQL去查询分析需要的内容。这套SQL简称HQL。HQL可以使不熟悉MapReduce 的用户很方便地利用SQL查询、汇总和分析数据。而MapReduce开发人员可以将自己编写的Mapper 和Reducer 作为插件来支持Hive 做更复杂的数据分析。Hive中的数据库和常见的关系数据库中的数据库的作用几乎是一样的,在生产环境中,如果表非常多,一般都会用数据库把表组织起来,形成逻辑组,这样可以有效防止大规模集群中表名冲突的问题。Hive数据库也是用来组织数据表的,它的本质就是数据仓库下的一个目录。
5.3.1Hive的数据类型
Hive的内置数据类型可以分为两大类,分别是基础数据类型和复杂数据类型,Hive的基础数据类型如表52所示,Hive的复杂数据类型如表53所示。


表52Hive的基础数据类型



数 据 类 型描述
tinyint1字节的有符号整数
smallint2字节有符号整数
int4字节有符号整数
bigint8字节有符号整数
float4字节单精度浮点数
double8字节双精度浮点数
double precisiondouble的别名,从Hive 2.2.0开始提供
decimal任意精度的带符号小数
numeric同样是decimal,从Hive 3.0开始
timestamp精度到纳秒的时间戳 
date以年/月/日形式描述的日期 
interval表示时间间隔 
string字符串 
varchar同string,字符串长度不固定 
char固定长度的字符串 
boolean布尔型



表53Hive的复杂数据类型



数 据 类 型描述
array一组有序字段,字段类型必须相同
map一组无序键值对。键的类型必须是原子类型,值可以是任意类型,同一个映射的键的类型必须相同,值的类型也必须相同
struct一组命名的字段,字段的类型可以不同

5.3.2Hive基础SQL语法
1. DDL 操作

DDL(Data Definition Language)是数据定义语言,与关系数据库操作相似。
1) 创建数据库
例如,创建一个名为bigdata的数据库,DDL语句为“create database bigdata;”,运行结果如下: 




显示数据库命令,DDL语句为“show database;”,运行结果如下: 




使用数据库,例如使用一个名为bigdata的数据库,DDL语句为“use bigdata;”,运行结果如下: 




2) 创建表
Hive在创建表时默认创建内部表,将数据移动到数据仓库指向的路径,而创建外部表(需要加关键字external),仅记录数据所在的路径,不对数据的位置做任何改变; Hive删除表时,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。创建表的语法如下: 

create table  #创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常

#用户可以用if not exist 选项来忽略这个异常

 external: 关键字,可以让用户创建一个外部表。
 comment: 可以为表与字段增加描述。
 partitioned by: 分区。
 clustered by: 数据汇总。
 sorted by: 按某列排序。
 buckets: 分桶,设置词句分桶才有效,如“set hive.enforce.bucketing=true;”。
 row format delimited: 按分割格式读取文件。

[fields terminated by char]: 每个列字段通过什么分割。

[collection items terminated by char]: 每个键值之间分割符。

[map keys terminated by char]: 每个键值对分割符。

[lines terminated by char]: 每行之间通过什么分割。
 stored as: 存储为不同文件格式。

[textfile]: 文本文件。

[sequencefile]: 序列化文件。

[rcfile]: 面向列的数据格式文件。

[inputformat input_format_classname outputformat output_format_classname]: 自定义的输入输出流。
 location: 在建表的同时指定一个指向实际数据的路径。

(1) 创建内部表。例如,创建一个名为student的内部表,DDL语句为: 

create table if not exists student(

id int,

name string,

birthday timestamp)

row format delimited

fields terminated by '\t'

lines terminated by '\n'

stored as textfile

location '/hive/warehouse/ student';

运行结果如下: 




查看当前数据库中表的命令为show tables,运行结果如下: 




查看数据库中的表,使用命令show tables in bigdata。
查看数据表的结构信息使用命令desc ,比如查看student 表结构信息的命令为desc student,运行结果如下: 




通过复制另一张表的表结构来创建表。要注意使用这种复制方式创建的表只复制表结构,不复制表中的数据,比如参照bigdata数据库中的student表的结构创建表名为student_copy的数据表,DDL语句为“create table if not exists student_copy like student;”,运行结果如下: 




(2) 创建外部表,例如创建一个名为student_external的外部表,DDL语句为: 

create external table if not exists student_external(

id int,

name string,

birthday timestamp)

row format delimited

fields terminated by '\t'

lines terminated by '\n'

stored as textfile

location '/hive/warehouse/external';

运行结果如下: 




(3) 创建分区表。例如创建一个名为teacher_partition的分区表,并设置成动态建立分区,DDL语句为: 

createtable teacher_partition

(id string,

name string)

partitioned by (country string ,state string);

set hive.exec.dynamic.partition=true; #开启动态分区,默认是false

set hive.exec.dynamic.partition.mode=nonstrict; #开启允许所有分区都是动态的,否
#则必须要有静态分区才能使用

set hive.exec.max.dynamic.partitions.pernode=1000; #动态分区最大数量

运行结果如下: 




(4) 创建桶表。在Hive分区表中,分区中的数据量过于庞大时,建议使用桶表。桶表是对某一列数据进行Hash取值以将数据打散,然后放到不同文件中存储。在分桶时,对指定字段的值进行Hash运算得到Hash值,并使用Hash值除以桶的个数再取余运算得到的值进行分桶,保证每个桶中有数据但每个桶中的数据不一定相等。 做Hash运算时,Hash()函数的选择取决于分桶字段的数据类型。桶表按某一列的值将记录进行分桶存放,即分文件存放,即将大表分解成一系列小表,涉及Join操作时,可以在桶与桶间关联即可,这样便减小了Join的数据量,提高了执行效率。
创建一个名为teacher_bucket的桶表,按照id分为4个桶,DDL语句为: 

create table teacher_bucket(

id string,

name string,

country string,

state string)

clustered by(id) into 4 buckets;

运行结果如下: 




3) 修改表
在Hive中,使用alter table子句来修改表的属性,实际上是修改表的元数据,而不会修改表中实际的数据。
(1) 对表重命名。例如,通过rename to命令将表student_copy表重命名为student01,DDL语句及运行结果如下: 




(2) 修改列信息。例如,通过change column命令对表student01的id字段重命名,将id字段重命名为uid,DDL语句及运行结果如下: 




(3) 修改字段的类型。例如,通过change column命令将uid的类型由int改为string,DDL语句及运行结果如下:  




(4) 增加列。例如,通过add columns命令将student01表添加grade和class两个列,DDL语句为“alter table student01 add columns(grade string,class string);”,DDL语句及运行结果如下: 




(5) 删除或替换列。例如,通过replace columns命令删除或替换student01表中的grade和class两个列,DDL语句及运行结果如下: 




4) 删除表。
例如,使用drop命令删除student01表,DDL语句及运行结果如下: 




2. DML 操作
DML(Data Manipulation Language)即数据操作语言,是用来对Hive数据库中的数据进行操作的语言。数据操作主要是如何向表中装载数据和如何将表中的数据导出,主要操作命令有load、insert等,insert语句的语法基本与标准SQL相同。
1) 装载数据
(1) 从本地路径下一次性装载大量的数据的方式。以上面建立的内部表teacher为例,DML语句为“load data local inpath '/hadoop/data'into table teacher;”。该语句会把本地的/ hadoop /data文件夹下的所有文件都追加到teacher表,其实际上就是一个文件的移动。如果加上local关键字,Hive会将本地文件复制一份然后再上传到指定目录,如果不加local关键字,Hive只会将HDFS上的数据移动到指定目录。DML语句及运行结果如下: 




(2) 覆盖表中已有的记录。需要加上overwrite关键字。以teacher为例,DML语句为“load data local inpath '/data.txt' overwrite into table teacher;”。
(3) 装载分区表数据。分区表在DML命令中需要指定分区,以分区表teacher_partition为例,DML语句为“load data local inpath '/data.txt' overwrite into table teacher_partitionpartition (country='US',state='CA');”,运行结果如下: 




2) 插入数据
(1) 通过标准SQL插入数据。例如,向teacher 表插入一条记录,DML语句为“insert into teacher(id,name,city,state) values(5,'aliy','CA','BD');”,运行结果如下: 




(2) 通过查询语句向表中插入数据。例如,将teacher表的数据插入teacher01表中, DML语句为“insert into teacher01 select * from teacher;”,运行结果如下: 




注意,通过查询语句向表中插入数据时要保证两个表的格式是一致的,这里的一致指的是要保证查询结果的格式和插入表的格式一致。加overwrite表示对源表数据进行覆盖。如果是分区表,则必须用partition指定分区。
(3) 导出数据。使用insert子句可以将数据导出到本地(加local)或HDFS,例如将teacher表中的数据导出到本地的'/hadoop/data'目录下,DML语句为“insert overwrite local directory '/hadoop/data' select * from teacher;”,运行结果如下: 




(4) 删除、更新数据。Hive从0.14版本开始支持事务和行级更新,但默认是不支持的,需要一些附加配置。要想支持行级update、delete,需要配置Hive支持事务。在此介绍表全删除命令truncate,DML语句为“truncate table teacher;”,运行结果如下: 



3. DQL 操作
DQL(Data Query Language)即数据查询语言,实现数据的简单查询,主要操作命令有select、where等。可以在查询时对数据进行排序、分组等操作,如sort by、order by、group by等,同时支持嵌套查询,例如执行DQL语句对teacher表按城市名称进行分组,同时查询出教师在同一城市数量大于1的城市。DML语句为“select count(*) from teacher group by city having count(*)>1;”。



5.4本章小结
本章主要介绍了Hive的架构、安装和基本操作,因为Hive的安装需要MySQL数据库,因此也相应介绍了MySQL的安装。本章的重点是Hive的基本操作,主要是DDL、DML、DQL基本操作。