大数据之Hive总结(上)

什么是Hive

  • Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。
  • Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类SQL 查询语言,称为 HQL,它允许熟悉 SQL 的用户查询数据,降低了把应用程序转移到Hadoop上的难度。
  • Hive 没有专门的数据格式,可以很好的工作在 Thrift 之上,有控制分隔符,也允许用户指定数据格式。用户可以非常*地组织 Hive 中的表,只需要在创建表的时候声明Hive数据中的列分隔符和行分隔符,Hive 就可以解析数据。

简单来说,就是

  1. Hive是基于HDFS之上的一个数据仓库
  2. Hive基于Hadoop之上的一个数据分析引擎(可以看成一个翻译器)
    • Hive 2.x 以前:SQL -----> Hive ----> MapReduce执行
    • Hive 2.x 以后:推荐使用Spark作为SQL的执行引擎(只针对Hadoop 3.x以前)
  3. Hive支持SQL的一个子集(HQL)

Hive的优缺点

  • 优点:
    1. 操作接口采用了sql,简化开发,减少学习成本
    2. 避免手写mapreduce程序
    3. 优点在于处理大数据
    4. 支持自定义函数
  • 缺点:
    1. hive的sql表达能力有限(HSQl)
    2. hive效率低。hive执行延迟较高,适用场景大多用在对实时性要求不强的情景

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总结(上)

四、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数据库的优化器

  1. RBO:基于规则的优化器
  2. CBO:基本上都是CBO,基于成本的优化器

补充:Oracle中的索引的类型

  1. B树索引:默认
  2. 位图索引

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 ',';
  1. 导入HDFS的数据 load data inpath ‘/scott/student.csv’ into table student;
  2. 导入本地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列映射需要注意的问题。

  1. 没有访问Hbase行时间戳的方式,只会返回最新版本的行。
  2. Hbase的键必须进行显示定义。