目录
1.Hive入门
1.1 什么是Hive
1.2 Hive的数据存储
1.3 Hive的系统架构
1.4 Metastore
1.5 数据库与数据仓库的区别
2.Hive安装部署
2.1 下载
2.2 安装MySQL
2.3 安装hive
3.Hive基础使用
3.1 Hive操作之命令行方式
3.2 Hive操作之JDBC方式
3.3 查询后信息显示配置
3.4 Hive的日志配置
4.Hive核心实战
4.1 数据库操作
4.2 表的操作
4.2.1 创建表
4.2.2 加载数据
4.2.3 查看表信息
4.2.4 表增加字段及注释、删除表
4.2.5 修改表名
4.2.6 指定列和行的分隔符
4.3 数据类型
4.3.1 基本数据类型
4.3.2 复合数据类型
4.4 表类型:内部表、外部表
4.5 内部分区表
4.5.1 分区表:
4.5.2 创建分区表
4.5.3 加载数据到指定分区
4.5.4 添加分区
4.5.5 查看所有的分区信息
4.5.6 删除分区
4.5.7 针对已有的分区如何上传数据
4.5.8 多个分区字段的使用
4.5.9 查询数据
4.6 外部分区表(最常用)
4.7 总结
4.8 表类型:桶表 + 视图
4.8.1 桶表
4.8.2 视图
4.8 数据处理综合案例
5.Hive高级函数实战
5.1 分组排序取topN
5.1.1 需求每个科目的前三名, 数据如下所示:
5.1.2 row_number()、rank() 、dense_rank()的区别
5.2 行转列(多行转成1列)
5.3 列转行(把一列数据转成多行)
5.4 排序函数
5.5 分组和去重函数
Hive:由Facebook开源用于解决海量结构化日志的数据统计。
Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。只能用来分析Hadoop中的结构化数据
本质是:将HQL转化成MapReduce程序
1)Hive处理的数据存储在HDFS
2)Hive分析数据底层的实现是MapReduce
3)执行程序运行在Yarn上
1. Hive2.x 开始官方不建议使用MapReduce引擎了,建议使用Tez或Spark引擎
2. 大数据计算引擎:
1)MapReduce
2)Tez(没有被广泛使用,通常和Hive一起使用)
3)Spark
4)Flink (在实时计算领域优于SPARK, 也支持在yarn上执行)
3. select * from table 不会产生MapReduce任务
Hive不支持修改和删除,侧重查询分析
数据库与数据仓库的本质区别是OLTP和OLAP的区别
版本选择及下载参考:https://hive.apache.org/downloads.html
略
cp hive-env.sh.template hive-env.sh
export HADOOP_HOME=/opt/module/hadoop-2.7.2
javax.jdo.option.ConnectionURL
jdbc:mysql://linux01:3306/metastore?serverTimezone=Asia/Shanghai
JDBC connect string for a JDBC metastore
javax.jdo.option.ConnectionDriverName
com.mysql.jdbc.Driver
Driver class name for a JDBC metastore
javax.jdo.option.ConnectionUserName
root
username to use against metastore database
javax.jdo.option.ConnectionPassword
123456
password to use against metastore database
!!需要手动创建hive元数据库metastore,注意此库必须是latin1,否则会出现奇怪问题!所以推荐手动创建!并且创建库之前不能有任意的hive操作,否则自动创建出来的库表将使用mysql默认的字符集,仍然报错!
!!另一种方法是修改mysql的配置文件,让mysql默认编码集就是latin1,这样hive自动创建的元数据库就是latin1的了,但是这已修改将会影响整个mysql数据库,如果mysql中有其他库,这种方式并不好。
hadoop.proxyuser.root.hosts
*
hadoop.proxyuser.root.groups
*
当 MySQL 部署好,Hive 配置修改好之后,启动 metastore 并不会自动初始化 metastore 库,需要手动执行初始化操作。Hive 自带了 schematool 用于初始化 metastore,命令如下:
bin/schematool -dbType mysql -initSchema
# 进入hive
bin/hive
# 选择数据库
hive> use default;
# 创建表
hive> create table t1 (id int, name string);
# 插入数据
hive> insert table t1 (id, name) values(1, "sanqian");
# 查看数据
hive> select * from t1;
优点:每列都是对齐的,方便查看
# 启动hiveserver2服务
bin/hiveserver2
# 启动beeline
bin/beeline
# 连接hiveserver2
beeline> !connect jdbc:hive2://linux01:10000
需要输入mysql的用户名和密码,如下图所示
0: jdbc:hive2://linux01:10000> show databases;
+----------------+
| database_name |
+----------------+
| default |
+----------------+
1 row selected (1.593 seconds)
0: jdbc:hive2://linux01:10000> use default;
No rows affected (0.138 seconds)
0: jdbc:hive2://linux01:10000> show tables;
+-----------+
| tab_name |
+-----------+
| t1 |
+-----------+
1 row selected (0.146 seconds)
0: jdbc:hive2://linux01:10000> select * from t1;
+--------+----------+
| t1.id | t1.name |
+--------+----------+
| 1 | sanqian |
+--------+----------+
1 row selected (1.922 seconds)
0: jdbc:hive2://linux01:10000>
org.apache.hive
hive-jdbc
2.3.9
package com.sanqian.hive;
import java.sql.*;
/**
* JDBC操作Hive
* 注意: 需要先启动hiveserver2服务
*/
public class HiveJdbcDemo {
public static void main(String[] args) throws SQLException {
// 指定hiveserver2的url链接
String jdbcUrl = "jdbc:hive2://192.168.21.101:10000";
// 获取连接,这里的user是指linux中的用户名,password随便指定即可
Connection conn = DriverManager.getConnection(jdbcUrl, "root", "any");
//获取Statement
Statement stmt = conn.createStatement();
//查询sql
String sql = "select * from t1";
//执行sql
ResultSet res = stmt.executeQuery(sql);
//循环读取结果
while(res.next()){
System.out.println(res.getInt("id") + "\t" + res.getString("name"));
}
}
}
hive> set hive.cli.print.current.db=true
> ;
hive (default)> set hive.cli.print.header=true;
hive (default)> select * from t1;
OK
t1.id t1.name
1 sanqian
Time taken: 6.35 seconds, Fetched: 1 row(s)
hive (default)>
set hive.cli.print.current.db=true;
set hive.cli.print.header=true;
hive.cli.print.header
true
hive.cli.print.current.db
true
查看hive历史操作命令
tail -10 ~/.hivehistory
Hive的log默认存放在/tmp/root/hive.log目录下(当前用户名下)
修改hive的log存放日志到/opt/module/hive-2.3.9/logs
mv hive-log4j2.properties.template hive-log4j2.properties
mv hive-exec-log4j2.properties.template hive-exec-log4j2.properties
# 查看数据库列表
show databases;
# 创建数据库
create database mydb1;
# 选择数据库
use default;
# 删除数据库
drop database mydb1;
创建一个数据库会增加/user/hive/warehouse增加一个目录
会在metastore数据的dbs表中增加一行记录
create table t2(
id int comment 'ID',
stu_name string comment 'name',
stu_birthday date comment 'birthday',
online boolean comment 'is online'
)row format delimited fields terminated by '\t';
注意:写HQL语句时不能时使用table加空格,可以使用space
行默认分隔符:\n (使用默认就行)
列默认分隔符:^A (可以使用ctrl + V ctrl + A 敲出)
数据
1 zhangsan 2022-10-02 true
2 lisi 2022-10-01 false
3 wangwu 2022-10-03 NULL
加载到表中
load data local inpath '/opt/lwx1087471/hive_data/t2.txt' into table t2;
# 查看有哪些表
show tables;
# 查看表信息
desc t2;
# 查看创建表的信息
show create table t2;
hive (default)> show tables;
OK
tab_name
t1
t2
t3
Time taken: 0.018 seconds, Fetched: 3 row(s)
hive (default)> desc t2;
OK
col_name data_type comment
id int ID
stu_name string name
stu_birthday date birthday
online boolean is online
Time taken: 0.034 seconds, Fetched: 4 row(s)
hive (default)> show create table t2;
OK
createtab_stmt
CREATE TABLE `t2`(
`id` int COMMENT 'ID',
`stu_name` string COMMENT 'name',
`stu_birthday` date COMMENT 'birthday',
`online` boolean COMMENT 'is online')
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
'field.delim'='\t',
'serialization.format'='\t')
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
'hdfs://linux01:9000/user/hive/warehouse/t2'
TBLPROPERTIES (
'transient_lastDdlTime'='1664829544')
Time taken: 0.093 seconds, Fetched: 18 row(s)
hive (default)>
#增加字段
alter table t2_bak add columns(address string);
# 删除表
drop table t2_bak
# 清空表
runcate table 表名
清空管理表,只清空数据
不能清空外部表
hive (default)> alter table t2 rename to t2_bak;
相应的HDFS的目录也会变化
create table t4(
id int comment 'ID',
stu_name string comment 'name',
stu_birthday date comment 'birthday',
online boolean comment 'is online'
)row format delimited fields terminated by '\t' lines terminated by '\n';
通常情况下不需要手动指定行分隔符使用默认\n就行
Hive有三种复杂数据类型ARRAY、MAP 和 STRUCT。ARRAY和MAP与Java中的Array和Map类似,而STRUCT与C语言中的Struct类似,它封装了一个命名字段集合,复杂数据类型允许任意层次的嵌套。
综合实战:
1)ARRAY字段存储用户的兴趣爱好
2)使用MAP字段存储学生的考试成绩
3)使用STRUCT字段存储员工地址信息
create table student(
id int comment 'ID',
name string comment 'name',
favors array comment 'favors',
scores map comment 'scores',
address struct
)row format delimited
fields terminated by '\t'
collection items terminated by ','
map keys terminated by ':'
lines terminated by '\n';
1 zhangsan english,sing,swing chinese:80,math:90,english:100 beijing,shanghai
2 lisi games,coding chinese:79,math:85,english:95 guangzhou,shenzhen
load data local inpath '/opt/xxx/hive_data/student.txt' into table student;
hive (default)> select favors[0] from student;
OK
_c0
english
games
hive (default)> select scores['chinese'] from student;
OK
_c0
80
79
hive (default)> select address.home_addr from student;
OK
home_addr
beijing
guangzhou
内部表:
外部表:
内部表和外部表可以相互转化:
# 内部表转外部表
alter table tblName set tblproperties('external'='true')
# 外部表转内部表
alter table tblName set tblproperties('external'='false')
create table partition_1(
id int comment 'ID',
name string comment 'name'
)partitioned by (dt string)
row format delimited
fields terminated by '\t';
查看表信息
数据:原始数据不需要带分区字段
1 zhangsan
2 lisi
加载数据到分区表
load data local inpath '/opt/xxx/partition_1.txt' into table partition_1 partition(dt='20221004');
alter table partition_1 add partition(dt='20221005');
hive (default)> show partitions partition_1;
OK
partition
dt=20221004
dt=20221005
alter table partition_1 drop partition(dt='20221005');
(1)使用load 加载数据
(2)使用put 传到对应的HDFS分区目录下
创建表
create table partition_2(
id int comment 'ID',
name string comment 'name'
)partitioned by (year int, school string)
row format delimited
fields terminated by '\t';
准备数据
1 zhangsan
2 lisi
3 wangwu
加载数据到分区
load data local inpath '/opt/xxx/partition_2.txt' into table partition_2 partition(year=2022, school='xk');
load data local inpath '/opt/xxx/partition_2.txt' into table partition_2 partition(year=2022, school='english');
load data local inpath '/opt/xxx/partition_2.txt' into table partition_2 partition(year=2021, school='xk');
load data local inpath '/opt/xxx/partition_2.txt' into table partition_2 partition(year=2021, school='english');
查看数据
select * from partition_2 where year=2022 and school='xk';
创建表:会在/data/ex_par创建一个目录
create external table ex_par(
id int comment 'ID',
name string comment 'name'
)partitioned by (dt string)
row format delimited
fields terminated by '\t'
location '/data/ex_par';
加载数据
load data local inpath '/opt/lwx1087471/partition_2.txt' into table ex_par partition(dt='20221004');
删除分区
alter table ex_par drop partition(dt='20221004');
绑定已有的数据到指定分区
alter table ex_par add partition(dt='20221005') location '/data/ex_par/dt=20221004';
第二种方式工作中更常用(95%)
方式1: load data .... partition
方式2: 创建目录,上传数据,绑定已有的数据到指定分区。
使用场景:当按照某字段就行分区时,会出现数据倾斜的情况,这时可以使用桶表。从源头解决数据倾斜问题。
# 创建桶表
create table bucket_tb(
id int comment 'ID'
)clustered by (id) into 4 buckets;
# 加载数据到临时表
load data local inpath '/opt/lwx1087471/ids.txt' into table b_source;
# 开启分桶功能
set hive.enforce.bucketing=true
# 插入数据
insert into table bucket_tb select id from b_source where id is not null;
会产生四个文件
采样
hive (default)> select * from bucket_tb tablesample(bucket 1 out of 4 on id);
OK
bucket_tb.id
16
12
8
4
Time taken: 0.276 seconds, Fetched: 4 row(s)
提高查询效率
普通表join会产生笛卡尔积,使用桶表join会避免笛卡尔积
使用视图可以降低查询的复杂度
视图时一个逻辑表(虚拟表),删除视图不会给其他表造成任务影响
函数的基本操作
1)查看所有内置函数:show functions;
2)查看指定函数的信息:desc function FUNC;
3)查看指定函数的扩展信息:desc function extended FUNC;
hive支持的函数要比mysql多
窗口函数
格式:函数 over( partition by 字段 ,order by 字段 window_clause )
row_number():增加行号函数
over():函数工作的数据窗口
创建表
create external table student_score(
id int,
name string,
sub string,
score int
)row format delimited
fields terminated by '\t'
location '/data/student_score';
上传数据
hadoop fs -put score.txt /data/student_score/
写HQL
select * from
(select *, row_number() over(partition by sub order by score desc) as num from student_score
) as s where s.num<=3;
运行结果
区别:
1)row_number() : 增加行号,从1,...n 不重复
2)rank() : 排序允许并列,一旦有并列跳号,总数不会变
3)dense_rank() : 排序允许并列,一旦有并列不跳号,总数会减少
row_number()
rank()
dense_rank()
三个函数:
一般和group by 一起使用
create external table student_favors(
name string,
favor string
)row format delimited
fields terminated by '\t'
location '/data/student_favors';
zs swing
zs footbal
zs sing
zs codeing
zs swing
hadoop fs -put student_favors.txt /data/student_favors/
select name,COLLECT_LIST(favor) as favors from student_favors group by name;
select name,COLLECT_SET(favor) as favors from student_favors group by name;
select name,CONCAT_WS(',',COLLECT_SET(favor)) as favors from student_favors group by name;
三个函数
案例
create external table student_favors_2(
name string,
favors_list string
)row format delimited
fields terminated by '\t'
location '/data/student_favors_2';
zs swing,footbal,sing
ls codeing,swing
hadoop fs -put student_favors_2.txt /data/student_favors_2/
select explode(split(favors_list, ',')) from student_favors_2;
select name,favor from student_favors_2 lateral view
explode(split(favors_list, ',')) t1 as favor;
排序
案例:
select id from bucket_tb order by id;
设置reduce个数:set mapreduce.job.reduces=2
select id from bucket_tb distribute by id sort by id;
select id from bucket_tb cluster by id;
group by 和distict的区别
需求:统计t1表中 去重后name的数据量
方式一:使用distinct
select count(distinct name) from t1;
方式二: 使用group by
selec count(*) from (select name from group by name) temp
使用方式一会把所有的数据shuffle到一个reduce中去做统计,性能不高。使用group by性能更高。