Hive学习
Hive
Hive是Hadoop的一个数据仓库工具,它可以将结构化的数据文件映射到一张数据表之中持久化在HDFS上,并提供类似于SQL的HQL语言来对数据表进行增、删、改、查等操作。它底层会将HQL语句转化为MapReduce任务进行执行。
作为Hadoop的数据仓库,故其为建立在Hadoop上的数据仓库基础架构,其数据分为两种:元数据和数据,元数据存储在关系型数据库之中,而数据持久化在HDFS上。
此外,Hive不支持OLTP(联机事务处理)。反而更接近成为一个OLAP(联机分析技术)工具,毕竟Hadoop被设计出就是用于处理的数据规模是非常大的,因此提交查询和返回结果是可能具有非常大的延时的。如果用户需要对这些大规模的数据使用OLTP功能的话,那么应当使用一个NOSQL的数据库,例如和Hadoop结合使用的HBase等。
大部分的数据仓库应用程序是基于SQL的关系型数据库实现的,故此降低了这些应用移植到Hadoop上的障碍。故用户只需懂得SQL就可以对Hive进行简单的数据操纵。
Hive的安装
我们知道Hive是基于Hadoop基础上的一种数据仓库,其元数据是通过关系型数据库进行存储的,故其先决条件是Hadoop集群和关系型数据库(这里使用MySQL)
(注意:Hive默认使用derby数据库,由于其只能存在一个连接,我们将其改为MySQL)
- 准备安装MySQL的Hadoop集群和Hive的安装的压缩包
- 解压安装包
- 配置环境变量(将Hive的安装位置加入到环境变量之中)
- 修改Hive的配置
(Hive的配置信息在\({HIVE_HOME}/conf/hive-default.xml.template文件下,如果我们需要对Hive的配置信息做出修改时,我们需要先在\){HIVE_HOME}/conf/目录下创建hive-site.xml文件,然后将要修改的配置信息放在此文件中。)-
hive-site.xml
<!--设置mr程序中间产生结果的hdfs临时存储路径--> <property> <name>hive.exec.scratchdir</name> <value>/tmp/hive</value> </property> <property> <name>hive.exec.local.scratchdir</name> <value>/home/hyxy/tmp/hive</value> </property> <!--设置hive连接数据库使用的用户名--> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>hyxyhive1</value><!--用户名--> </property> <!--设置数据库使用的用户的密码--> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>123456</value> </property> <!--设置hive数据库连接的url--> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://master:3306/hive?createDatabaseIfNotExist=true</value> </property> <!--设置hive中存储的元数据的关系型数据库,默认为derby数据库--> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <!--设置hive元数据的默认存储位置--> <property> <name>hive.metastore.warehouse.dir</name> <value>/user/hive/warehouse</value> </property> <!--设置cli显示当前数据库(便于操作)--> <property> <name>hive.cli.print.current.db</name> <value>true</value> </property> <!--设置动态分区的最大分区数,默认1000--> <property> <name>hive.exec.max.dynamic.partitions</name> <value>1000000</value> </property> <!--设置没个节点的动态分区的最大值,默认100--> <property> <name>hive.exec.max.dynamic.partitions.pernode</name> <value>1000000</value> </property> <property> <name>hive.server2.thrift.bind.host</name> <value>master</value> </property> <!--配置beeline远程客户端连接时的用户名和密码。 这个用户名要在对应的hadoop的配置文件core-site.xml中也配>置 --> <!--使用beeline连接hiveserver2所使用的用户名--> <property> <name>hive.server2.thrift.client.user</name> <value>hyxy</value> </property> <!--使用beeline连接hiveserver2所使用的用户的密码--> <property> <name>hive.server2.thrift.client.password</name> <value>123456</value> </property>
-
core-site.xml
<property> <name>hadoop.proxyuser.hyxy.hosts</name> <value>*</value> </property> <property> <name>hadoop.proxyuser.hyxy.groups</name> <value>*</value> </property>
-
- 安装完成
Hive的使用
在Hive的安装目录的bin文件夹下有三个常使用的命令
- hive
本地使用hive工具,对hive进行操作 - hiveserver2
开启hiveserver2服务后,集群上的其他节点可通过beeline连接此节点的hive(Hive一个客户端) - beeline
使用beeline连接指定的hive客户端
数据类型
Hive的数据类型除了在一般关系型数据库中含有的集中基本数据类型,它还具有一些特有的集合数据类型。
-
基本数据类型
数据类型 长度 TINYINT 1byte有符号整数 SMALLINT 2byte有符号整数 INT 4byte有符号整数 BIGINT 8byte有符号整数 BOOLEAN 布尔类型,true或false FLOAT 单精度浮点数 DOUBLE 双精度浮点数 STRING 字符序列。可以指定字符集,可以使用单引号或者双引号 TIMESTAMP 整数,浮点数或者字符串 BINARY 字节数组 -
集合数据类型
|数据类型 | 描述 |
|ARRAY | 数组,用来存储具有相同数据类型的变量的集合|
|MAP | MAP是一组键值对元组集合|
|STRUCT | 与c语言的结构体相类似,通过点来访问变量值|
Hive操作
Hive的操作是通过HQL语句进行操作,HQL语句与SQL语句有着非常大的相似之处(可简单的看成SQL),HQL在底层实现的时候将其转化为MapReduce程序进行执行。
- 对表结构进行操作
- 建立表结构
Create table 表名 [if not exists]( 字段1 数据类型 comment "描述信息" 字段2 数据类型 comment "描述信息", … ) [partitioned by (字段1 数据类型 [字段n 数据类型])] [clustered by(id)into (num) buckets] [row format delimited [fields terminated by '分隔符1'] [collection items terminated by '分隔符'] [map keys terminated by '分隔符'] [lines terminated by '分隔符'] ] [stored as 文件格式(TEXTFILE)] [Location '存储路径']; -- 注:
- 修改表结构
Alter table 表名 +操作 例如: Alter table table1 rname table2; Alter table table2 add partition(partition_key=值) ...
- 建立表结构
- 对表数据进行操作
-
插入数据
插入数据的方式有三种:- 单个数据插入(与SQL的语法一致)
Insert into (字段1,字段2,字段n) values(值1,值2,值n)。由于数据单个插入也会运行一个mr程序,故此我们常用数据加载的方式插入数据 - 将数据以文件形式上传(移动,拷贝)至HDFS的指定位置
- Hadoop fs -put 本地文件路径 表所在路径
- Hadoop fs -mv(-cp) 数据文件所在路径 表所在路径
- 将数据以文件形式加载到表中(加载HDFS中的数据文件会将与路径下的文件删除)
- Load data local inpath '本地路径' [overwrite] into table 表名
- Load data inpath '本地路径' [overwrite] into table 表名
注意:后两种需要在创建表的时候指定相应的分隔符,数据文件中的数据的分隔符也要与之相对应,当数据插入到Hive后,我们可以查看到HDFS上表所在路径下会出现所对应的相应的文件,文件名的格式类似为000000-0等编号信息
- 单个数据插入(与SQL的语法一致)
-
查询数据
由于其查询语言与SQL有着过人的相似之处,故其也支持一些类似于UNION,UNION ALL,JOIN,子查询等方式。
-
重点
读时模式与写时模式
-
读时模式
所谓的读时模式就是,Hive不会在数据加载的时候进行对数据的验证,而是在数据查询的时候运行。因而它可以使得数据的加载十分迅速 -
写时模式
写时模式恰恰与读时模式相反,Hive会在数据加载的时候对数据进行验证,二在数据加载的时候不问不管。故此其查询效率是是有所提升的 -
两者的选取
由于其在对数据进行验证的时候的不同,故两者在不同场景下使用的效率而会受到相对的影响,用户必须在两者之间权衡。
管理表与托管表
-
管理表
管理表也叫内部表,我们一般默认创建的表都是管理表,默认的存储位置(仓库目录)由配置项中的 hive.metastore.warehouse.dir 决定,当然,我们也可以自己指定其存储路径。在这种表中,hive会(或多或少)控制着hive中数据的生命周期,当该管理表被删除的时候,其所存储的数据以及元数据都会被删除。因此,管理表不适合与其他的应用一起共享管理数据。 -
托管表
托管表也叫外部表,在在创建表的时候通过 EXTERNAL 关键词来指定其为外部表。当指定该表为外部表的时候,Hive 知道该表数据并非由自己管理,也就不会将此表放入到自己的仓库目录下,因此我们在创建外部表的时候必须指定其存储的位置。然而事实上,在外部表定义的时候,Hive 都不会去检查该存储路径的正确性,这就意味着我们可以把创建数据推迟到创建表之后才进行。
当外部表被删除的时候,Hive是不会删出持久化在HDFS上的数据,它只会将元数据删除 -
两者的转化
两者的转化可以通过 ALTER 语句(修改表结构)来进行转化,具体使用如下:内部转外部 alter table tableA set TBLPROPERTIES('EXTERNAL'='true') 外部转内部 alter table tableA set TBLPROPERTIES('EXTERNAL'='false')
-
两者的优缺点
- 大多数情况下两者并没有什么区别(drop语句除外)。
- 管理表:表被删除时,表中的元数据与持久化在HDFS上的数据都会被删除。适用于数据只由Hive应用管理的场景。
- 外部表:表被删除时只会删除存在表中的元数据,持久化在HDFS上的数据是不会被删除的。适用于数据由多种应用共同管理的场景
分区与分桶
-
分区
-
为什么会有分区
Hive是基于大数据基础上的一个数据仓库,其所存储的数据并非小量,而是可能达到TB,PB甚至及以上。而且随着系统运行的时间增长,其数据的增长量也是十分之大的。但是,Hive在扫描数据的时候,一般默认全表扫描,这样会导致大量的不必要的数据扫描,降低了查询的效率。 -
怎么分区
根据业务的不同,选择较为高效的分区方式 -
分区的语法:
PARTITIONED BY(COL_NAME DATA_TYPE)
值得注意的是:
- Hive分区使用的字段是表外字段,而MySQL使用的是表内字段;
- Hive的分区名区分大小写;
- Hive分区的本质是在该表下建立目录,其分区列是伪列,并不真实存在表中;
- 一张表可以有一个或多个分区,分区下可以嵌套多个分区,以规定分区是的字段顺序进行嵌套。
-
分区的意义
分区的主要目的就是为了减少不必要的数据扫描,减少数据扫描的范围(查询语句通过where指定分区),提高查询的效率。 -
创建分区表
定义表结构的时候指定分区,例如创建分区表 part_table,字段为uid(int),uname(string),根据country(string)和date(string)进行嵌套分区(先对country进行分区,再对date进行分区),每个字段以','间隔。create table if not exists part_table( uid int, uname string ) PARTITIONED BY (country string,date_time string) row format delimited fields terminated by ',';
-
动态分区与静态分区
- 静态分区
静态分区是指在将数据插入表中的时候指定其所在的分区。例如:insert into part_table(uid,uname) values(18,'zhangsan') partition(country='China',date_time='2016-11-11'); -- 或者是用数据加载的方式 load data local inpath '数据文件所在的本地路径' into table part_table partition(country='China',date_time='2016-11-11')
- 动态分区
所谓的动态分区就是在插入数据的时候不指定其分区,然后根据数据来自己确定分区。(注:此种方式不能使用数据加载的方式进行数据插入),例如:
使用动态分区技术的时候,必须设置 动态分区是不严格的,这个设置可以在hive-site.xml中设置,也可在sql执行时临时设置,使其暂时生效。如果使用动态分区是所要分区数过多,建议修改每个节点的分区数的最大值和分区数的最大值-- 从data_table表中选取数据插入到part_table中, insert into part_table partition(country,date_time) select * from data_table; -- 注,查询的数据必须列数必须与要插入的表的列相吻合。
hive.exec.dynamic.partition.mode=nonstrict
- 静态分区
-
-
分桶
-
什么是分桶
分区提供了一个隔离数据和优化查询的便利的方式。但是,并非所有的数据集都可以形成合理的分区,尤其是当防止数据倾斜的时候。而分桶是将数据分解管理的另一技术,是对数据进行更细粒度的划分。 -
怎么分桶
Hive 默认是采用对某一列的每个数据进行 hash ,使用 hashcode 对桶的个数进行取余,然后确定该数据应当是放在哪个桶中。 -
分桶的语法
CLUSTERED BY (col_name, col_name, ...)
注:若分区与分桶同时存在的话,分桶必须在分区之后
-
分桶的意义
- 由于桶的数量是一定的,所以它没有数据波动。
- 有利于高效的执行map-side JOIN。
- 分桶的效率一定高于分区。
-