想玩明白Hive哪有那么容易,十分钟你都看不完

HIVE


什么是数据仓库

数据仓库是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策


什么是Hive

由FaceBook开源用于解决海量结构化日志的数据统计

Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,
并提供类SQL查询功能

1、Hive处理的数据存储在HDFS
2、Hive分析数据底层的实现是MapReduce
3、执行程序运行在Yarn上

Hive依赖于HDFS存储数据,Hive将HQL转换成MapReduce执行,
所以说Hive是基于Hadoop的一个数据仓库
实质就是一款基于HDFS的MapReduce计算框架,对存储的HDFS中的数据进行分析和管理

Hive架构

1、Hive的用户接口层,CLI即Shell命令行,CLI最常用

2、Hive将元数据存储在数据库中,连接到这些数据库的模式有三种,
单用户模式、多用户模式、远程服务器模式 

3、完成HQL的查询语句分析、语法分析、编译、优化以及查询计划的生成。
生成的查询计划存储在HDFS中,并由MapReduce调用执行

4、Hive的数据存储在HDFS中,针对大部分的HQL查询请求,Hive内部自动转换成MapReduce任务执行

Hive的优缺点

优点
1、操作接口采用类SQL语法,提供快速开发的能力
2、避免了去写MapReduce,减少开发人员的学习成本
3、Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合
4、Hive优势在于处理大数据,对于处理小数据没有优势,因为Hive的执行延迟比较高
5、Hive支持用户自定义函数,用户可以根据自己的需求实现自己的函数

缺点
1、迭代式算法无法表达
2、数据挖掘方面不擅长
3、Hive自动生成的MapReduce作业,通常情况下不够智能化
4、Hive调优比较困难,粒度较粗

Hive和数据库比较

由于Hive采用了类似SQL的查询语言,因此很容易将Hive理解为数据库。
其实从结构上来看,Hive和数据库除了拥有类似的查询语言,再无类似之处。
数据库可以用在Online的应用中,但是Hive是为了数据仓库为设计。
查询语言
由于SQL被广泛的应用再数据仓库中,因此,专门针对Hive的特性设计了类SQL的查询语言HQL。
数据存储位置
Hive是建立再Hadoop之上的,所有Hive的数据都是存储再HDFS中的。
而数据库则可以将数据保存在块设备或者本地文件系统中
数据更新
由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少。
因此,Hive中不建议对数据的改写,所有的数据都是在加载的时候确定好的
而数据库中的数据通常是需要经常进行修改的,因此可以增删改查
索引
Hive在加载数据的过程中不会对数据进行任何处理,甚至不会对数据进行扫描
因此,也没有对数据中的某些Key建立索引
Hive要访问数据中满足条件的特定值时,需要暴力扫描整个数据,
因此访问延迟比较高,Hive不适合在线数据查询

由于MapReduce的引入,Hive可以并行访问数据,因此即使没有索引,
对于大数据量的访问,Hive仍然可以体现出优势

数据库中,通常会针对一个或者几个列建立索引,因此对于少量的特定条件的数据的访问,
数据库可以由很高的效率,较低的延迟。
执行
Hive中大多数查询是通过Hadoop提供的MapReduce来实现的,
而数据库通常有自己的执行引擎
执行延迟
由于Hive是建立在Hadoop之上的,因此Hive的可扩展性是Hadoop的可扩展性是一致的
而数据库由于ACID语义的严格限制,扩展行非常有限
数据规模
由于Hive建立在集群上并可以利用MapReduce进行并行计算,因此可以支持很大规模的数据
数据库可以支持的数据规模较小

Hive基本数据类型

Hive数据类型Java数据类型长度例子
TINYINTbyte1byte有符号整数2
SMALINTshort2byte有符号整数20
INTint4byte有符号整数20
BIGINTlong8byte有符号整数20
BOOLEANboolean布尔类型,true或者falseTRUE FALSE
FLOATfloat单精度浮点数3.14159
DOUBLEdouble双精度浮点数3.14159
STRINGstring字符系列。可以指定字符集。可以使用单引号或者双引号。‘now is the time’ “for all good men”
TIMESTAMP时间类型
BINARY字节数组

Hive集合数据类型

数据类型描述语法示例
STRUCT和c语言中的struct类似,都可以通过“点”符号访问元素内容。例如,如果某个列的数据类型是STRUCT{first STRING, last STRING},那么第1个元素可以通过字段.first来引用。struct()
MAPMAP是一组键-值对元组集合,使用数组表示法可以访问数据。例如,如果某个列的数据类型是MAP,其中键->值对是’first’->’John’和’last’->’Doe’,那么可以通过字段名[‘last’]获取最后一个元素map()
ARRAY数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,编号从零开始。例如,数组值为[‘John’, ‘Doe’],那么第2个元素可以通过数组名[1]进行引用。Array()

类型转化

Hive的原子数据类型是可以进行隐式转换的,类似于Java的类型转换

隐式转换规则如下
1、任何整数类型都可以隐式地转换为一个范围更广地类型,如TINYINT可以转化为INT,INT可以转换为BIGINT
2、所有整数类型、FLOAT和STRING类型都可以隐式地转换成DOUBLE
3、TINYINT、SMALLINT、INT都可以转换为FLOAT
4、BOOLEAN类型不可以转换为任何其他地类型

DDL数据操作


创建数据库

create database mydb;
mydb是自定义数据库名称


create database if not exists mydb comment 'create my db named dbname' 
with dbproperties('createtime'='2022-03-19')
if not exists避免要创建的数据库已经存在错误

comment是给数据库加注释

with dbproperties后面跟的键值,描述该数据库的属性信息,eg:作者是谁,创建日期是什么时候等;

create database mydb location '/db_hive.db'
创建数据库指定数据库在HDFS上存放地位置

查询数据库/表

查看建表语句
show create database mydb

显示数据库
show databases

过滤显示查询地数据库
show databses like 'db_hive*'
 
查看数据库详情
desc database db_hive

显示数据库详细信息
desc database extended db_hive

切换当前数据库
use mydb

查看数据库地数据表
show tables
show tables in mydb

查询表结构
desc formatted hive_table

删除数据库

删除空数据库
drop database db_hive

如果删除的数据库不存在,采用if exists判断
drop database if exists db_hive

如果数据库不为空,采用cascade,强制删除
drop databse db_hive cascade

修改数据库

alter database db_hive set dbproperties('createtime'='2022-03-20')

数据库表操作

建表语法

1、create table 创建一个指定名字的表
2、if not exists 忽略已存在表异常
3、external 关键字可以让用户创建一个外部表
4、comment 为表和列添加注释
5、partitioned by 创建分区表
6、clustered by 创建分桶表
7、sorted by 不常用
8、row format delimited 指定序列化的分隔符
9、stored as 指定存储文件类型
10、location 指定表在HDFS上的存储位置
11、like 允许用户复制现有的表结构,但是不复制数据

内部表

默认创建的表都是管理表,也称为内部表。
Hive创建内部表时,会将数据移动到数据仓库指向的路径;
删除内部表时,会将元数据和数据一起删除

外部表

Hive不认为外部表完全拥有这份数据
若创建外部表,仅记录数据所在的路径,不对数据的位置做任务改变
删除外部表的时候,只删除元数据,不删除数据

应用场景:每天收集到的网站日志定期流向HDFS文本文件,在外部表的基础上做大量的统计分析,
用到的中间表、结果表使用内部表存储,数据通过select insert进入内部表

分区表

分区表实际上就是对应一个HDFS文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。
Hive中的分区就是分目录,把一个大的数据集根据业务需要分割成为小的数据集。
在查询时通过where子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多

分桶表

分区针对的是数据的存储路径,分桶针对的是数据文件
分桶是将数据集分解成更容易管理的若干部分的另一个技术

根据查询结果创建表

create table if not exists hive_table as select id,name,age from mytable

根据已经存在的表结构创建表

create table if not exists hive_table like mytable

创建内部表

create table mytable(id int,name string,age int)
row format delimited fields terminated by '\t'
stored as textfile
location '/user/hive/warehouse/mytable'

创建外部表

create external table mytable(id int,name string,age int)
row format delimited fields terminated by '\t'
stored as textfile
location '/user/hive/warehouse/mytable'

创建分区表

create table hive_table(id int,name string,age int)
partitioned by(month string)
row format delimited fields terminated by '\t'

创建动态分区表

create table hive_table(id int,name string,age int,createtime string)
partitioned by (,createtime string)
row format delimited fields terminated by ‘\t’

根据表字段进行动态分区

set hive.exec.dynamic.partiton.mode=nonstrict;
设置分区表为非严格模式
hive.sexc.max.dynamic.partitions=1000
所有MR的节点上默认分区数 1000
hive.sexc.max.dynamic.partitions.pernode=100
每个MR的节点上,最大可以创建多少个动态分区 100
hive.exec.max.created.files=10000
整个MR job中,最大可以创建多少个HDFS文件
hive.error.on.empty.partition=false

insert into table 表名 partition(动态分区字段)
select 字段,。。。 from dept;

hive3.0 动态分区不用花partition就能进行动态分区

创建二级分区表

create table hive_table(id int,name string,age int)
partitioned by(month string,day string)
row format delimited fields terminated by '\t'

创建分桶表

create table hive_table(id int,name string,age int)
clustered by(id) 
into 4 buckets
row formated delimited fields terminated by '\t'

修改表名

alter table hive_table rename to new_hive_table

内部表和外部表互相转换

alter table mytable set tblproperties('external'='true')

'external'='true' 将内部表转为外部表
'external'='false' 将外部表转为内部表

增加分区

alter table hive_table add partition(month='202203') partition(month='202204') 

删除分区

alter table hive_table drop partition(month='202203') partition(month='202204')

HDFS数据与分区表产生联系

修复分区
msck repair table 表名
会检查表名路径下的文件是否为分区文件,如不是,则修改元数据使其成为分区表

添加分区
alter table 表名 add partition(分区字段=‘’)
可以将已经存在的非分区文件转为分区表

上传数据不设置分区时,会HIVE_DEFAULT_PARTITION

增加/修改/替换列信息

添加列
alter table hive_table add columns(desc string)

更新列
alter table hive_table chang column id sid int

替换列
alter table hive_table replace columns(desc string,dname string,loc string)
replace是替换表中所有字段,可以用于删除表字段

删除表

drop table hive_table

DML数据操作

向表中装载数据(Load)

语法
1、load data 表示加载数据
2、local 表示从本地加载数据到Hive表;否则从HDFS加载数据到Hive表
3、inpath 表示加载数据的路径
4、overwrite 表示覆盖表中已有数据,否则表示追加
5、into table 表示加载到哪张表
6、hive_table 表示具体的表
7、partition 表示上传到指定分区
加载本地文件到Hive
load data local inpath 'xx/xx.txt' into table default.hive_table

加载HDFS文件搭配Hive中
load data inpath 'user/hive/xx.txt' into table default.hive_table

加载数据覆盖表中已有的数据
load data inpath 'user/hive/xx.txt' overwrite into table default.hive_table

通过查询语句向表中插入数据(Insert)

基本插入数据
insert into table hive_table partition(month='202203') 
values(1,'zhangsan')

根据单表查询结果插入数据
insert overwrite table hive_table partition(month='202203')
select id,name from mytable where month='202202'

根据多张表查询结果
from hive_table
insert overwrite table hive_table partition(month='202202')
select id,name where month='202202'
insert overwrite table hive_table partition(month='202201')
select id,name where month='202202'

创建表并加载数据(As Select)

创建表并指定在HDFS上的位置
create table if not exists hive_table(id int,name string)
row format delimited fields terminated by '\t'
location '/user/hive/warehouse/hive_table'

上传数据到HDFS上
dfs -put /opt/modele/datas/test.txt
/user/hive/warehouse/hive_table

Import数据到指定Hive表中

import table hive_table partition(month='202203')
from '/user/hive/warehouse/hive_table'

Insert数据导出

将查询的结果导出到本地
insert overwrite local directory '/opt/module/datas/export/hive_local'
select * from hive_table

将查询的结果格式化导出到本地
insert overwrite local directory '/opt/module/datas/export/hive_local'
row format delimited fields terminated by '\t'
select * from hive_table

将查询到的结果导出到HDFS上(没有local)
insert overwrite directory '/opt/module/datas/export/hive_local'
row format delimited fields terminated by '\t'
select * from hive_table

Hadoop命令导出到本地

dfs -get /user/hive/warehouse/hive_table/month=202203/000000_0
/opt/module/datas/export/hive_table.txt;

Hive Shell命令导出

bin/hive -e 'select * from default.hive_table;'
/opt/module/datas/export/hive_table.txt;

Export导出到HDFS上

export table detault.hive_table to
'/user/hive/warehouse/export/hive_table'

Sqoop导出

bin/sqoop export \
--connect jdbc:mysql://hadoop1001:2206/company \
--username root \
--password 123456 \
--table hive_table \
--num-mappers 1 \
--export-dir /company \
--input-fields-terminated-by '\t'

num-mappers 启动N个map来并行导入/出数据,默认4个

清楚表中的数据(Truncate)

Truncate只能删除管理表,不能删除外部表中的数据
truncate table hive_table

查询

全表和特定列查询

全表查询
select * from hive_table

特定列查询
select id,name from hive_table

列别名
select id as sid,name nm from hive_table

算术运算符

运算符描述
A+BA和B 相加
A-BA减去B
A*BA和B 相乘
A/BA除以B
A%BA对B取余
A&BA和B按位取与
A|BA和B按位取或
A^BA和B按位取异或
~AA按位取反

常用函数

求总行数 count
select count(*) cnt from emp

求最大值 max
select max(sal) max_sal from emp

求最小值 min
select min(sal) min_sal from emp

求和 	sum
select sum(sal) sum_sal from emp

求平均值 avg
select avg(sal) avg_sal from emp

Limit语句

Limit子句用于限制返回的行数
select * from emp limit 5;

Where语句

使用where子句,将不满足条件的行过滤掉
selsect * from emp where sal>1000

比较运算符

操作符支持的数据类型描述
A=B基本数据类型如果A等于B则返回TRUE,反之返回FALSE
A<=>B基本数据类型如果A和B都为NULL,则返回TRUE,其他的和等号(=)操作符的结果一致,如果任一为NULL则结果为NULL
A<>B, A!=B基本数据类型A或者B为NULL则返回NULL;如果A不等于B,则返回TRUE,反之返回FALSE
A<B基本数据类型A或者B为NULL,则返回NULL;如果A小于B,则返回TRUE,反之返回FALSE
A<=B基本数据类型A或者B为NULL,则返回NULL;如果A小于等于B,则返回TRUE,反之返回FALSE
A>B基本数据类型A或者B为NULL,则返回NULL;如果A大于B,则返回TRUE,反之返回FALSE
A>=B基本数据类型A或者B为NULL,则返回NULL;如果A大于等于B,则返回TRUE,反之返回FALSE
A [NOT] BETWEEN B AND C基本数据类型如果A,B或者C任一为NULL,则结果为NULL。如果A的值大于等于B而且小于或等于C,则结果为TRUE,反之为FALSE。如果使用NOT关键字则可达到相反的效果。
A IS NULL所有数据类型如果A等于NULL,则返回TRUE,反之返回FALSE
A IS NOT NULL所有数据类型如果A不等于NULL,则返回TRUE,反之返回FALSE
IN(数值1, 数值2)所有数据类型使用 IN运算显示列表中的值
A [NOT] LIKE BSTRING 类型B是一个SQL下的简单正则表达式,如果A与其匹配的话,则返回TRUE;反之返回FALSE。B的表达式说明如下:‘x%’表示A必须以字母‘x’开头,‘%x’表示A必须以字母’x’结尾,而‘%x%’表示A包含有字母’x’,可以位于开头,结尾或者字符串中间。如果使用NOT关键字则可达到相反的效果。
A RLIKE B, A REGEXP BSTRING 类型B是一个正则表达式,如果A与其匹配,则返回TRUE;反之返回FALSE。匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。

Like和RLike

1、使用Like运算选择类似的值
 select * from emp where sal LIKE '2%';
2、选择条件可以包含字符或数字 R表示正则匹配
 select * from emp where sal RLIKE '[2]';

逻辑运算符

操作符含义
AND逻辑并
OR逻辑或
NOT逻辑否
select * from emp where sal>1000 and deptno=30;
select * from emp where sal>1000 or deptno=30;
select * from emp where deptno not IN(30, 20);

Group By

Group by 语句通常会和聚合函数一起,按照一个或者多个列队结果进行分组,
然后对每个组执行聚合操作

select t.deptno,avg(t.sal) avg_sal from emp t group by t.deptno

Having

having和where不同点
1、where针对表中的列发挥作用,查询数据;
	having针对查询结果中的列发挥作用,筛选数据分组函数
2、where后面不能分组函数,而having后面可以使用
3、having只用于group by分组统计语句

select deptno, avg(sal) avg_sal from emp group by deptno having avg_sal > 2000;

Join

Hive支持通常的SQL Join语句,但是只支持等值连接,不支持非等值连接

内连接 只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
select e.empno, e.ename, d.deptno from emp e join dept d on e.deptno
 = d.deptno;

左外连接 JOIN操作符左边表中符合WHERE子句的所有记录将会被返回
select e.empno, e.ename, d.deptno from emp e left join dept d on e.deptno
 = d.deptno;

右外连接 JOIN操作符右边表中符合WHERE子句的所有记录将会被返回
select e.empno, e.ename, d.deptno from emp e right join dept d on e.deptno
 = d.deptno;

满外连接 将会返回所有表中符合WHERE语句条件的所有记录。
如果任一表的指定字段没有符合条件的值的话,那么就使用NULL值替代
select e.empno, e.ename, d.deptno from emp e full join dept d on e.deptno
 = d.deptno;

多表连接
SELECT e.ename, d.deptno, l.loc_name FROM   emp e 
JOIN   dept d ON d.deptno = e.deptno 
JOIN   location l ON d.loc = l.loc;

排序

Order by 	全局排序,一个Reduce
select * from emp order by sal

ASC			升序(默认)
select * from emp order by sal asc

DESC		降序
select * from emp order by sal desc

多列排序
select ename, deptno, sal from emp order by deptno, sal ;

每个MapReduce内部排序(Sort by)
select * from emp sort by empno desc;

分区排序 Distribute By

Distribute By 类似MR中partition,进行分区,结合sort by使用
注意:Hive要求Distribute by语句要写在Sort by语句之前

select * from emp distribute by deptno sort by empno desc

分桶排序Cluster By

当distribute by和sort by字段相同时,可以使用cluster by方式
cluster by 除了具有disteibute by的功能外还兼具sort by的功能。
但是排序只能升序排序,不能指定排序规则为ASC或者DESC

等价写法
select * from emp cluster by deptno
select * from emp disterbute by deptno sort by deptno

分桶抽样查询

TABLESAMPLE(BUCKET x OUT OF y) 。
y必须是table总bucket数的倍数或者因子
select * from stu_buck tablesample(bucket 1 out of 4 on id)

空字段赋值

NVL:给值为NULL的数据赋值,她的格式是NVL(string1,replace_with)
它的功能是如果string1为Null,则NVL函数返回replace_with的值,否则返回string1的值,
如果两个参数都为NULL,则返回NULL

select nvl(comm,-1) from emp

case when then else end

判断方法 , 类似if else用法
select 
  dept_id,
  sum(case sex when '男' then 1 else 0 end) male_count,
  sum(case sex when '女' then 1 else 0 end) female_count
from 
  emp_sex
group by
  dept_id;
  
case sex when '男' then 1 else 0 end 判断条件,是男是则返回1 否则返回0

行转列

concat(string A/col,string B/col。。。)返回输入字符串连接后的结果,支持任务个输入字符串

concat_ws(separator,str1,str2,...) 它是一个特殊形式的concat().第一个参数剩余参数键的分隔符。
分隔符可以是于剩余分隔符一样的字符串

collect_set(col) 函数只接受基本数据类型,它的作用主要是讲某字段的值进行去重汇总,产生array类型字段

concat

select concat('a','-','b','-','c');
输出结果
a-b-c
------------------------
select concat(deptno,'-',dname) from dept;
输出
10-ACCOUNTING
20-RESEARCH
30-SALES
40-OPERATIONS
-------------------------

concat_ws
select concat_ws('-','a','b','c')
第一位放分隔符,后面放参数
输出结果
a-b-c
---------------------------

collect_set

select collect_set(id) from student1;
输出 【“1001”,“1002”,“1003”】

collect_list

select collect_list(id) from student1;
输出 【“1001”,“1002”,“1003”,“1001”,“1002”,“1003”,“1001”,“1002”,“1003”】

列转行

explode(col) 讲hive一列中复杂的array或者map结构拆分成多行
lateral view 用于和split,explode等UDTF一起使用,它能够讲一列数据拆成多行数据,
在此基础上可以对拆分后的数据进行聚合

select
    movie,
    category_name
from 
    movie_info 
lateral view explode(category) table_tmp as category_name;

篇幅太长了,剩下的下一篇总结


版权声明:本文为weixin_43870646原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。