Hive
简介
概述
- Hive是由Facobook开发的后来贡献给了Apache的一套用于进行数据仓库管理的工具,使用类SQL语言来对分布式文件系统中的PB级别的数据来进行读写、管理以及分析
- Hive基于Hadoop来使用的,底层的默认计算引擎使用的是MapReduce。Hive利用类SQL(HQL,Hive Query Language)语言来操作数据,但是底层是将SQL转化为MapReduce来执行,也因此,Hive更适合于处理离线分析场景
- Hive可以屏蔽掉不同语言之间的差异性,降低了大数据的入门门槛
- Hive的支持的计算引擎:MapReduce、Tez、Spark。底层默认使用的是MapReduce,但是效率最高的是Spark
- 在Hive中,库名、表名、字段名、字段类型、分区、分桶等信息属于元数据,是存储在数据库中,默认支持的是Derby。但是Derby本身是一个单连接的数据库,所以会将Hive的元数据库替换为MySQL。注意:Hive的元数据是存储在数据库的,Hive的数据是放在HDFS上!
版本
- 到目前为止,Hive一共有4个版本:Hive1.X和Hive4.X
- Hive4.X一共有3个小版本(alpha1、alpha2、beta1),目前都是测试版
- 目前,在市面上,Hive1.x到Hive3.x都在使用,其中Hive1.x逐渐被抛弃,现在市面上使用较多的是Hive2.x和Hive3.x
- Hive3.x需要基于Hadoop3.x使用,Hive2.x需要基于Hadoop2.x使用
安装
安装MySQL
-
CentOS7自带MySQL,需要先卸载这个MySQL:
shrpm -qa | grep -i mysql | xargs rpm -ev --nodeps rpm -qa | grep -i mariadb | xargs rpm -ev --nodeps
-
扇出MySQL可能残留的配置文件
shfind / -name mysql | xargs rm -rf find / -name my.cnf | xargs rm -rf rm -rf /var/lib/mysql/
-
进入预安装目录,上传或者下载MySQL的安装包
shcd /opt/presoftware/ # 上传/下载MySQL的安装包
-
解压
shtar -xvf mysql-5.7.33-1.el7.x86_64.rpm-bundle.tar
-
安装MySQL,并且顺序不能颠倒!!!
shrpm -ivh mysql-community-common-5.7.33-1.el7.x86_64.rpm rpm -ivh mysql-community-libs-5.7.33-1.el7.x86_64.rpm rpm -ivh mysql-community-devel-5.7.33-1.el7.x86_64.rpm rpm -ivh mysql-community-libs-compat-5.7.33-1.el7.x86_64.rpm rpm -ivh mysql-community-client-5.7.33-1.el7.x86_64.rpm rpm -ivh mysql-community-server-5.7.33-1.el7.x86_64.rpm
-
启动MySQL
shsystemctl start mysqld
-
第一次安装MySQL,会自动生成初始密码
shgrep "temporary password" /var/log/mysqld.log
-
登陆MySQL
shmysql -u root -p # 输入初始密码
-
默认情况下,MySQL的规则要求,密码至少要包含12个字符,至少包含1个大写字母、1个小写字母、1个数字和1个特殊符号。在实际开发过程中,密码肯定要求复杂度;学习环境下,密码不需要这么复杂,所以需要修改MySQL的密码规则
mysql-- 修改MySQL关于密码长度的限制 set global validate_password_length = 4; -- 修改MySQL关于密码字符类型的限制 set global validate_password_policy = 0;
-
修改MySQL的密码
mysql-- 为root@localhost设置密码为root set PASSWORD FOR 'root'@'localhost' = "root";
-
配置MySQL的远程连接
mysql-- 开放权限 grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option; -- 策略生效 flush privileges;
-
测试
sh# 退出MySQL quit; # 重新进入MySQL mysql -u root -p
安装Hive
-
进入预安装目录,上传或者下载Hive的安装包。注意:上课使用的Hive的安装包不是官网提供的,而是我们自己编译好的。官网提供的Hive安装包,最多支持Spark2,但是现在使用的比较多的Spark3版本,也因此,实际过程中,如果想要让Hive支持Spark3,就意味着需要自己下载Hive的源代码并且修改,自己编译!!!
shcd /opt/presoftware/ # 上传/下载安装包
-
解压
shtar -xvf apache-hive-3.1.3-bin.tar.gz -C /opt/software/
-
重命名
shcd ../software/ mv apache-hive-3.1.3-bin/ hive-3.1.3
-
配置环境变量
sh# 编辑文件 vim /etc/profile.d/hivehome.sh # 在文件中添加 export HIVE_HOME=/opt/software/hive-3.1.3 export PATH=$PATH:$HIVE_HOME/bin # 保存退出,生效 source /etc/profile.d/hivehome.sh # 测试 hive --version
-
解决Hive的日志jar包冲突的问题
shcd hive-3.1.3/lib/ mv log4j-slf4j-impl-2.17.1.jar log4j-slf4j-impl-2.17.1.bak
-
给Hive添加MySQL的连接驱动
-
修改Hive的配置
shcd ../conf # 编辑文件 vim hive-site.xml
在文件中添加
xml<?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <!--Hive元数据库--> <property> <name>hive.metastore.db.type</name> <value>mysql</value> </property> <!--MySQL连接地址--> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://hadoop01:3306/hive?useSSL=false</value> </property> <!--MySQL驱动--> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <!--MySQL用户名--> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> </property> <!--MySQL密码--> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>root</value> </property> <!--Hive元数据的存储位置--> <property> <name>hive.metastore.warehouse.dir</name> <value>/user/hive/warehouse</value> </property> <!--Hive元数据的约束--> <property> <name>hive.metastore.schema.verification</name> <value>false</value> </property> <!--Hive元数据的访问位置--> <property> <name>hive.metastore.uris</name> <value>thrift://hadoop01:9083</value> </property> <!--Hive服务的访问端口--> <property> <name>hive.server2.thrift.port</name> <value>10000</value> </property> <!--Hive服务监听的主机--> <property> <name>hive.server2.thrift.bind.host</name> <value>hadoop01</value> </property> <!--Hive的自动认证--> <property> <name>hive.metastore.event.db.notification.api.auth</name> <value>false</value> </property> <property> <name>datanucleus.schema.autoCreateAll</name> <value>true</value> </property> </configuration>
-
初始化元数据库
sh# 进入MySQL mysql -u root -p
在MySQL中建立元数据库,注意元数据库的编码必须是latin1
mysqlcreate database hive character set latin1; -- 退出 quit;
初始化元数据库
shschematool -initSchema -dbType mysql --verbose
-
因为Hive基于Hadoop的(利用HDFS存储数据,利用MapReduce计算),所以需要启动Hadoop
shstart-all.sh
-
启动Hive的元数据服务
shhive --service metastore &
-
启动Hive
shhive
基础语法
注意问题
- Hive中,如果不指定,默认只有一个库
default
- 在Hive中,每一个database对应了HDFS上的一个目录。默认情况下,database是放在HDFS的
/user/hive/warehouse
下 - 在Hive中,没有主键的概念,也不支持主键
- Hive中的每一个表也对应了HDFS上的一个目录
- Hive中建表的时候需要指定字段之间的间隔符号,表一旦建好,字段之间的间隔符号就不能变化!
- Hive的数据默认支持insert和select,默认不支持delete和update。如果需要支持delete和update操作,那么在建表的时候,需要指定Hive数据在HDFS上的文件存储类型必须是
orc
和parquet
格式
库操作
-
查看所有的库
sqlshow databases;
-
建库
sqlcreate database demo;
-
删除库。要求库必须是空的
sqldrop database demo;
-
建库的时候指定库的存储位置
sqlcreate database demo location '/demo.db';
-
利用正则表达式过滤符合要求的库
sqlshow databases like 'd*';
-
建库的时候,判断库是否存在。如果不存在,那么建库
sqlcreate database if not exists demo;
-
强制删除库
sqldrop database demo cascade;
-
使用库
sqluse demo;
-
建库的时候还给库指定属性
sqlcreate database demo2 with dbproperties('create_time'='2024-03-26');
-
描述库
sqldesc database demo2;
-
描述库的详细信息
sqldesc database extended demo2;
-
修改库的属性
sqlalter database demo2 set dbproperties('create_time'='024-03-27');
表及数据操作
-
创建表
sqlcreate table person ( id int, name string, age int);
-
插入数据
sqlinsert into table person values(1, 'Amy', 15);
转化为MapReduce执行
-
查询数据
sqlselect * from person;
-
加载数据 - 实际上就是将文件上传到HDFS上,加载速度和文件的上传速度相关
sqlload data local inpath '/opt/hive_data/person' into table person; -- load data 加载数据 -- local 本地 -- inpath 输入路径
-
删除表
sqldrop table person;
-
建立person表,指定字段之间的间隔符号是空格
sqlcreate table person ( id int, name string, age int) row format delimited fields terminated by ' '; -- row format 对数据进行按行的处理 -- delimited 对什么数据进行拆分 -- fields 字段、属性 -- terminated by ' ' 用什么拆分
-
查看所有的表
sqlshow tables;
-
描述表
sqldesc person
-
创建p2表,p2的表结构和person一样
sqlcreate table p2 like person;
-
如果p3表不存在,那么创建p3表,表结构和person一样
sqlcreate table if not exists p3 like person;
-
创建p4表,表结构以及数据都和person一样(复制person表)
sql-- 将person的数据全部查询出来,根据查询数据的结构来建立p4表并放入数据 create table p4 as select * from person; select * from p4;
-
将person表中age>=18的数据查询出来,放入p2表中
sqlinsert into table p2 select * from person where age >= 18;
注意 :
insert into
表示向表中追加数据,insert overwrite
先将表中的数据清空掉,然后再覆盖写入 -
从person表中查询数据,将id<5的数据覆盖到p2表中,将age<18的数据写入到p3表中
sqlfrom person insert overwrite table p2 select * where id < 5 insert into table p3 select * where age < 18;
-
将person表中id>5的数据查询出来放到HDFS的/person目录下,字段之间用
,
间隔sqlinsert overwrite directory '/person' row format delimited fields terminated by ',' select * from person where id > 5;
如果是将数据写到Hive之外的地方,此时只能使用
insert overwrite
,所以要求输出路径必须为空。如果输出路径不为空,那么会将输出路径下的所有文件给清空!!! -
Hive除了支持将结果写到HDFS上,还支持写到本地磁盘上
sqlinsert overwrite local directory '/opt/hive_demo' row format delimited fields terminated by '\t' select * from person where age >= 18;
同样,要求输出路径必须为空!!!
-
将person表重命名为p1
sqlalter table person rename to p1;
-
将p1表的id字段改为pid,类型改为string
sqlalter table p1 change column id pid string;
-
在p1表中新增字段:gender,类型是string
sqlalter table p1 add columns(gender string);
表结构
内部表和外部表
-
在Hive中,所有的表分为内部表(又叫管理表,Managed Table )和外部表(External Table)
-
一般而言,在Hive中,手动建表手动添加数据的表,大部分是内部表;在Hive中,建表管理HDFS上已经存在的数据,这个表称之为外部表
-
可以通过
sqldesc extended p1; -- 或者 desc formatted p1;
如果是内部表,那么
tableType
的值MANAGED_TABLE
;如果是外部表,那么tableType
的值EXTERNAL_TABLE
-
建立外部表
sqlcreate external table flows ( phone string, city string, name string, upFlow int, downFlow int ) row format delimited fields terminated by ' ' location '/flow';
-
查询数据
sql-- tablesample,抽样函数 select * from flows tablesample(5 rows);
-
删除内部表,那么对应的元数据和HDFS上的目录都会删除;删除外部表,那么只删除元数据但是不删除HDFS上的目录
-
在实际过程中,项目前期使用外部表,中后期使用内部表
-
内部表转化为外部表
sqlalter table p3 set tblproperties ( 'EXTERNAL' = 'true');
-
外部表转化为内部表
sqlalter table p3 set tblproperties ( 'EXTERNAL' = 'false');
分区表
-
分区表的最常见的作用也是对数据进行分类
-
案例
-
原始数据
sql-- wei 1 荀彧 2 荀攸 3 贾诩 4 郭嘉 -- shu 1 孙乾 2 简雍 3 糜竺 4 庞统 -- wu 1 陆逊 2 张昭 3 鲁肃 4 周瑜
-
在Hive中建表,管理数据,同时区分数据对应的国家
sqlcreate table heros ( id int, -- 编号 name string -- 姓名 ) partitioned by (country string) row format delimited fields terminated by ' ';
-
查看表
sqldesc heros;
-
将数据加载到表中。当向分区表中加载数据的时候,如果没有指定分区,那么会将数据放入默认分区
__HIVE_DEFAULT_PARTITION__
sqlload data local inpath '/opt/hive_data/wei' into table heros partition(country = 'wei'); load data local inpath '/opt/hive_data/shu' into table heros partition(country = 'shu'); load data local inpath '/opt/hive_data/wu' into table heros partition(country = 'wu');
-
-
在Hive中,每一个分区对应HDFS上一个单独的目录!!!
-
在分区表中,当查询数据的时候以分区作为查询条件,可以提高查询效率;如果进行跨分区查询,那么此时效率会降低
-
手动在HDFS上创建的目录,默认不会自动加载到Hive的元数据中
-
手动建立分区
sh# 在HDFS上建立目录,上传文件 hadoop fs -mkdir /user/hive/warehouse/demo.db/heros/country=qun hadoop fs -put qun /user/hive/warehouse/demo.db/heros/country=qun
在Hive中手动添加分区
sqlalter table heros add partition(country = 'qun') location '/user/hive/warehouse/demo.db/heros/country=qun'; -- 或者 修复分区 - 有可能会修复失败,如果修复失败,那么此时只能手动add msck repair table heros;
-
修改分区名
sqlalter table heros partition(country = 'qun') rename to partition(country = 'other');
-
删除分区
sqlalter table heros drop partition(country = '__HIVE_DEFAULT_PARTITION__');
-
需要注意的是,在Hive中,分区字段在原始数据中是不存在的,而是在加载数据的时候手动指定,所以分区实际上可以认为是数据的"伪列"。如果原始数据中包含了分区字段,那么此时就需要进行动态分区
-
动态分区
-
原始数据
sql1 other 吕布 2 wei 甘宁 3 shu 马岱 4 wei 王凌 5 shu 糜芳 6 shu 魏延 7 other 刘璋 8 wei 丁仪 9 wu 周平 10 shu 马忠
-
建立临时表
sqlcreate table heros_tmp ( hid int, h_country string, h_name string ) row format delimited fields terminated by ' ';
-
加载数据
sqlload data local inpath '/opt/hive_data/heros' into table heros_tmp; -- 测试 select * from heros_tmp tablesample(5 rows);
-
动态分区默认是不开启
sql-- 只对本次session有效,如果退出Hive重新进入,那么依然是严格模式 set hive.exec.dynamic.partition.mode = nonstrict;
-
将未分区表中的数据插入到分区表中 - 动态分区
sqlinsert into table heros partition(country) select hid, h_name, h_country from heros_tmp distribute by h_country;
-