什么是Hive
- Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。
- Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类SQL 查询语言,称为 HQL,它允许熟悉 SQL 的用户查询数据,降低了把应用程序转移到Hadoop上的难度。
- Hive 没有专门的数据格式,可以很好的工作在 Thrift 之上,有控制分隔符,也允许用户指定数据格式。用户可以非常自由地组织 Hive 中的表,只需要在创建表的时候声明Hive数据中的列分隔符和行分隔符,Hive 就可以解析数据。
简单来说,就是
- Hive是基于HDFS之上的一个数据仓库
- Hive基于Hadoop之上的一个数据分析引擎(可以看成一个翻译器)
- Hive 2.x 以前:SQL -----> Hive ----> MapReduce执行
- Hive 2.x 以后:推荐使用Spark作为SQL的执行引擎(只针对Hadoop 3.x以前)
- Hive支持SQL的一个子集(HQL)
Hive的优缺点
- 优点:
- 操作接口采用了sql,简化开发,减少学习成本
- 避免手写mapreduce程序
- 优点在于处理大数据
- 支持自定义函数
- 缺点:
- hive的sql表达能力有限(HSQl)
- hive效率低。hive执行延迟较高,适用场景大多用在对实时性要求不强的情景
Hive的体系架构
- 用户接口主要有三个:CLI,JDBC/ODBC和 WebUI
- CLI,即Shell命令行
- JDBC/ODBC 是 Hive 的Java,与使用传统数据库JDBC的方式类似。与另外两种接口不同的是,客户端不能直接通过JDBC/ODBC访问Hive,需要通过Thrift Server(1.x版本以前)或HiveServer2(2.x版本之后)来完成
- WebGUI是通过浏览器访问 Hive,只在Hive2.2版本以前才有
- Hive将元数据存储在数据库中(metastore),支持 derby、mysql等关系型数据库(官方建议使用MySQL)。Hive 中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等
- 解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化以及查询计划(plan)的生成。生成的查询计划存储在 HDFS 中,随后由执行器通过调用MapReduce执行
- Hive 的数据存储在 HDFS 中,大部分的查询由 MapReduce 完成,但是有些查询不会转换为MapReduce程序(包含 * 的查询,比如 select * from table 不会生成 MapRedcue 任务)
Hive的安装
Hive有三种安装模式,分别是嵌入式(内嵌)模式、本地模式和远程模式。
一、内嵌模式
- 元数据信息存储在内置的Derby数据库中
- 只运行建立一个连接
- 设置Hive的环境变量和核心配置文件hive-site.xml
- 初始化MetaStore:schematool -dbType derby -initSchema
二、本地模式
(本地安装mysql 替代derby存储元数据)
三、远程模式
(远程安装mysql 替代derby存储元数据)
本地模式和远程模式的差别不大,只是存储元数据的MySQL数据库和Hive是否装在同一台机器上面而已,所以区别就是核心配置文件hive-site.xml中的jdbc连接地址的不同。
- 本地模式和远程模式都需要安装MySQL数据库
- 要使用高版本的MySQL驱动
- 设置Hive的环境变量和核心配置文件hive-site.xml
- 初始化MetaStore:schematool -dbType mysql -initSchema
四、Hive的启动和关闭
下面所写的都是在终端上输入的shell命令
- 启动hive服务:hiveserver2
- 启动hive客户端:hive
- 静默模式启动:hive -S(不在终端界面上打印日志)
- 关闭:CTRL+c
Hive的数据类型
基本数据类型
数据类型 | 长度 | 例子 |
---|---|---|
tinyint | 1byte有符号整数 | 20 |
smallint | 2byte有符号整数 | 20 |
int | 4byte有符号整数 | 20 |
bigint | 8byte有符号整数 | 20 |
boolean | 布尔类型,true或者false | TRUE |
float | 单精度浮点数类型 | 3.14159 |
double | 双精度浮点数类型 | 3.14159 |
string | 字符串类型.可以指定字符集。可以使用单引号或者双引号 | ‘now is the time’,“for all good men” |
binary | 字节数组 |
所有的这些数据类型都是对Java中的接口的实现,因此这些类型的具体行为细节和Java中对应的类型是完全一致的。
要注意的是,有些SQL会提供限制最大长度的“字符数组”(即很多字符串)类型,但Hive不支持这种数据类型,Hive根据不同字段间的分隔符来对不同的文件格式进行判断。同时,Hadoop和Hive强调优化磁盘的读和写性能,而限制列的值的长度相对来说不重要。
在进行数据类型的比较时,Hive会隐式地将类型转换为两个数据类型中较大的那个类型。如将一个float类型的列和一个double类型的列作对比或者一个tinyint类型的值和另一个int类型的值作对比,就会将float类型转换为double类型,将tinyint类型转换int类型。而且如果有必要,也会将任意的整型类型转换为double类型,因此事实上都是同类型之间的比较。
集合数据类型
数据类型 | 描述 | 字面语法示例 |
---|---|---|
Struct | 结构类型,和C语言中的struct或者“对象”类似,可以包含不同数据类型的元素。这些元素可以通过“点语法”的方式来得到所需要的元素 | struct(‘John’,‘Doe’) |
Map | 集合类型,包含key-value键值对,可以使用数组表示法通过key来访问元素 | map(‘first’,‘JOIN’,‘last’,‘Doe’) |
Array | 数组类型,由一系列相同数据类型和名称的元素组成 | Array(‘John’,‘Doe’) |
大多数关系型数据库并不支持这些集合数据类型,因为它们会趋于破坏标准格式,而破坏标准格式所带来的一个实际问题是会增大数据冗余的风险,进而导致消耗不必要的磁盘空间,还有可能造成数据不一致,因为当数据发生时冗余的拷贝数据可能无法进行相应的同步。
然而,在大数据系统中,不遵循标准格式的一个好处就是可以提供更高吞吐量的数据。按数据集进行封装的话可以通过减少寻址次数来提高查询的速度,而如果根据外键关系关联的话则需要进行磁盘间的寻址操作,这样会有非常高的性能消耗。Hive中也没有键的概念,但是用户可以对表建立索引来提高查询速度。
时间类型
- Date:从Hive0.12.0开始支持
- Timestamp:从Hive0.8.0开始支持,Timestamp表示的是UTC时间。Hive本身提供了不同时区间互相转换的内置函数,即to_utc_timestamp函数和from_utc_timestamp函数。
- Timestamp的值可以是整数,也就是距离Unix新纪元时间(1970年1月1日,午夜12点)的秒数
- 也可以是浮点数,即距离Unix新纪元时间(1970年1月1日,午夜12点)的秒数,精确到纳秒(小数点后保留9位数)
- 还可以是字符串,即JDBC所约定的时间字符串格式,格式为: YYYY-MM-DD hh:mm:ss.ffffffff。
Hive的数据模型
Hive的数据存储
- 基于HDFS
- 没有专门的数据存储格式
- 存储结构主要包括:数据库、文件、表、视图
- 可以直接加载文本文件(.txt文件)
- 创建表时,指定Hive数据的列分隔符与行分隔符
Hive 中所有的数据都存储在 HDFS 中,Hive中包含以下数据模型:表(Table),外部表(External Table),分区(Partition),桶(Bucket),其在HDFS上对应的存储形式如下:
Hive | HDFS |
---|---|
表 | 目录 |
数据 | 文件 |
分区 | 目录 |
桶 | 文件 |
表
Inner Table(内部表)
- 与数据库中的 Table 在概念上是类似
- 每一个 Table 在 Hive 中都有一个相应的目录存储数据
- 所有的 Table 数据(不包括 External Table)都保存在这个目录中
- 删除表时,元数据与数据都会被删除
//举例:创建一个员工表 emp表
//数据 7654,MARTIN,SALESMAN,7698,1981/9/28,1250,1400,30
//创建一个员工表 emp1表,并且指定分隔符是:逗号
create table emp1
(empno int,
ename string,
job string,
mgr int,
hiredate string,
sal int,
comm int,
deptno int
)row format delimited fields terminated by ',';
Partition Table (分区表)
- Partition 对应于数据库的 Partition 列的密集索引
- 在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的数据都存储在对应的目录中
//举例:创建一个分区表,根据部门号deptno
create table emp_part (empno int,ename string, job string,mgr int,hiredate string, sal int, comm int)
partitioned by (deptno int)
row format delimited fields terminated by ',';
- 往分区表中插入数据:使用子查询
insert into table emp_part partition(deptno=10)
select empno,ename,job,mgr,hiredate,sal,comm from emp1 where deptno=10;
insert into table emp_part partition(deptno=20)
select empno,ename,job,mgr,hiredate,sal,comm from emp1 where deptno=20;
insert into table emp_part partition(deptno=30)
select empno,ename,job,mgr,hiredate,sal,comm from emp1 where deptno=30;
- 与关系型数据库类似,在Hive中,通过SQL的执行计划获知分区表提高的效率
在查询时,增加explain关键字,比如 explain select * from emp1 where deptno=10; 就可以打印出Hive的执行计划。
补充:Oracle中SQL的执行计划,要打印其执行计划,比Hive麻烦一点,同样是查询10号部门的员工,在Oracle中需要输入
explain plan for select * from emp where deptno=10;
select * from table(dbms_xplan.display);
补充:Oracle数据库的优化器
- RBO:基于规则的优化器
- CBO:基本上都是CBO,基于成本的优化器
补充:Oracle中的索引的类型
- B树索引:默认
- 位图索引
External Table(外部表)
- 指向已经在 HDFS 中存在的数据,可以创建 Partition
- 它和内部表在元数据的组织上是相同的,都是存在MySQL上,而实际数据的存储则有较大的差异,外部表的数据依然存储在HDFS上
- 外部表只有一个过程,加载数据和创建表同时完成,并不会移动到数据仓库目录中,只是与外部数据建立一个链接。当删除一个外部表时,仅删除该链接
create external table ext_student
(sid int,sname string,age int)
row format delimited fields terminated by ','
location '/students'; //指定数据的所在HDFS上的目录
Bucket Table (桶表)
- 类似Hash分区,桶表是对数据进行哈希取值,然后根据哈希值放到不同文件中存储。
- 需要设置环境变量:set hive.enforce.bucketing = true;
//根据员工的职位job建立桶表
create table emp_bucket
(empno int,
ename string,
job string,
mgr int,
hiredate string,
sal int,
comm int,
deptno int
)clustered by (job) into 4 buckets
row format delimited fields terminated by ',';
//插入数据
insert into table emp_bucket select * from emp1;
视图(View)
- 视图是一种虚(不存数据)表,是一个逻辑概念;
- 可以跨越多张表
- 视图建立在已有表的基础上, 视图赖以建立的这些表称为基表
- 视图可以简化复杂的查询
- 作用:简化复杂的查询
- 补充:物化视图可以缓存数据
create view view10
as
select * from emp1 where deptno=10;
Hive数据的导入
Hive支持两种方式的数据导入
- 使用load语句导入数据
- 使用sqoop导入关系型数据库中的数据
- 此外,Hive还可以通过HiveStorageHandler连接HBase、Cassandra等非关系型数据库。
使用load语句导入数据
load语句:相当于ctrl+x
数据文件:
student.csv
1,Tom,23
2,Mary,24
3,Mike,22
创建相应结构的表:注意:Hive默认分隔符是: tab键。所以需要在建表的时候,指定分隔符。
create table student(sid int,sname string,age int)
row format delimited fields terminated by ',';
- 导入HDFS的数据 load data inpath ‘/scott/student.csv’ into table student;
- 导入本地Linux的数据:load data local inpath ‘/root/temp/student.csv’ into table student;
使用sqoop导入关系型数据库中的数据
-
将关系型数据的表结构复制到hive中
sqoop create-hive-table --connect jdbc:mysql://localhost:3306/test --table username --username root --password 123456 --hive-table test
其中 --table username为mysql中的数据库test中的表 --hive-table test 为hive中新建的表名称 -
从关系数据库导入文件到hive中
sqoop import --connect jdbc:mysql://localhost:3306/test --username root --password 123456 --table t1 --hive-import
-
将hive中的表数据导入到mysql中
sqoop export --connect jdbc:mysql://localhost:3306/test --username root --password 123456 --table from_hive --export-dir /user/hive/warehouse/uv/dt=2011-08-03
连接HBase、Cassandra等非关系型数据库
HiveStorageHandler是Hive连接HBase、Cassandra等非关系型数据库的主要接口,需要定义一个定制的InputFormat、一个OutputFormat以及SerDe。当在nosql数据库上执行Hive查询时,nosql系统的资源消耗、执行效率比常规的基于HDFS的Hive和MapReduce job要慢。其中一部分原因源于服务器的socket连接资源消耗和对底层多个文件的合并过程,而从HDFS中典型的访问是完全顺序I/O,顺序I/O在现代磁盘上是非常快的。
创建一个指向Hbase表的Hive表
create table hbase_stocks(key int,name string,price float)
stored by 'org.apache.hadoop.hive.hbase.HbaseStorageHandler'
with serdeproperties("hbase.columns.mapping" = ":key,stock:val")
tblproperties("hbase.table.name" = "stocks");
创建一个指向已经存在的Hbase表的Hive表(也就是创建外部表)
create external table hbase_stocks(key int,name string,price float)
stored by 'org.apache.hadoop.hive.hbase.HbaseStorageHandler'
with serdeproperties("hbase.columns.mapping" = ":key,stock:val")
tblproperties("hbase.table.name" = "stocks");
和Hbase结合使用的Hive支持Hbase表和Hbase表的连接操作,也支持Hbase表和非Hbase表的连接操作。当将Hive中的数据导入到Hbase中时,需要注意,Hbase要求键是排重后唯一的,而Hive中并无此要求。还有一些Hive和Hbase列映射需要注意的问题。
- 没有访问Hbase行时间戳的方式,只会返回最新版本的行。
- Hbase的键必须进行显示定义。