6 Hive

一、Hive 是什么

​ Hive 是构建在 Hadoop 之上的数据仓库平台;它通过 SQL 解析引擎把 SQL 语句转译成 MapReduce 作业,并在 Hadoop 上运行;Hive 表是 HDFS 的文件目录,一个表对应一个目录名,如果有分区,则分区值对应子目录。

二、Hive 架构

在这里插入图片描述

解释图中元素

1、核心部分

​ 1)解析器:将SQL字符串转换成抽象语法树AST,这一步一般用第三方工具完成;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误;

​ 2)编译器:把AST翻译成逻辑执行计划,即将hql翻译成MapReduce任务;

​ 3)优化器:对逻辑执行计划进行优化,优化方案随着模版的不断迭代而改进;

​ 4)执行器:顺序执行所有的 job,如果 task 链不存在依赖关系,可以采用并发执行的方式执行 job。

2、元数据库

​ 元数据用于存放 Hive 库的基础信息,它存在关系数据库中,如 mysql。元素据包括:数据库信息、表名、列表和列的分区及其属性,表的属性,表的数据所在的目录。

三、托管表与外部表

Hive 表分为两类,一个是托管表(内部表),一个是外部表。

托管表是只在 hive 中使用,外部表示 hive 之外也使用,它们下面两个方面有区别:

3.1 数据存储

托管表:数据存储在 hive 仓库目录下,是指定的。我指定为:/apps/hive/warehouse

外部表:外部表可存在 hdfs 的任意目录下。

3.2 数据删除

托管表:删除元数据和数据。

外部表:只删除元数据。

四、分区和桶

4.1 分区

​ 分区其实就是在一个 hdfs 大的文件夹下面的子文件夹,它不是表的上面的结构,分区可以帮助我们来缩小查询的范围从而提高效率。在导入数据的时候,可以根据数据中的特定列把数据放到指定分区中,即指定文件夹中。

4.2 桶

​ 桶是表上面的附加结构,可以提高查效率。桶对应于 MapReduce 的输出文件分区,一个作业产生的桶和 reduce 任务个数相等。

​ 我个人理解是表对应的是文件夹,分区是文件夹下的子文件夹,而桶就是对应于子文件夹里的文件了,我们把具有相同特征的内容放到一个文件里,即一个桶中。分区针对的是数据的存储路径;分桶针对的是数据文件。

五、Hive和数据库的比较

5.1 查询语言

​ hive与数据库唯一相似的地方就是查询语言相似,sql和hql语法和类似

5.2 数据存储位置

​ hive是建立在Hadoop之上的,所以数据都是存储在hdfs中,而数据库则将数据保存在本地文件系统中。

5.3 数据更新

​ hive中不支持数据的更新,要想更新数据就必须先把之前的文件删除,然后再上传,而数据库则支持灵活更新。

5.4 索引

5.5 执行引擎

​ hive的引擎为mr、tez、spark,而数据库有自己的执行引擎。

5.6 执行延迟

​ hive的执行需要启动jvm和mapreduce作业,所以如果处理小规模的数据时,会明显慢于数据库;

5.7 可扩展新

​ 因为hive构建于hadoop上,所以可以狠方面的扩展节点数量,而数据库由于ACID语义的严格限制,扩展性非常有限。

5.8 数据规模

​ hive支持的数据规模远远大于数据库

六、查询

6.1 排序

  • order by: 保证全局有序,在一个 reducer 中进行排序并输出。在 strict mode(hive.mapred.mode=strict)下,必须搭配 limit 使用,这是为了防止这个 reducer 任务花费的时间过长

  • sort by:sort by 在将数据发送给 reducer 前会将数据排序,sort by 只能保证同一个 reducer 中的数据有序

  • distribute by:对查询数据进行分区

  • cluster by:distribute by 和 sort by 的结合,默认这两个后面跟的列名相同,如果想用不同的列,则必须分开指定:

SELECT col1, col2 FROM t1 DISTRIBUTE BY col1 SORT BY col2 DESC

6.2 函数

1. nvl

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

2. 行转列
  1. concat(string A/col, string B/col···):返回输入字符串连接后的结果,支持任意个输入字符串;

    1. concat_ws(separator, str1, str2,…):特殊形式的concat,第一个参数指定分隔符,如果分隔符为null,返回值也为null
    2. collect_set(col):将某字段的值进行去重汇总,产生array类型字段

例:把星座和血型一样的人归类到一起,

nameconstellationblood_type
孙悟空白羊座A
大海射手座A
宋宋白羊座B
猪八戒白羊座A
凤姐射手座A

结果如下:

射手座,A 大海|凤姐

白羊座,A 孙悟空|猪八戒

白羊座,B 宋宋

解题:

select bn, concat_ws("|", collect_set(name)) 
from 
	(select concat_ws(",", constellation, blood_type) bn, name from tb) t1
group by t1.bn;
3. 列转行

​ explode(col):将hive一列中复杂的array或者map结构拆分成多行;

​ lateral view:

​ 用法:lateral view udtf(expression) tableAlias as columnAlias

​ 解释:用于和split,explode等udtf一起使用,它能将一列数据拆分成多行数据,在此基础上可以对拆分后的数据进行聚合

例:

元数据集:

moviecategory
《疑犯追踪》悬疑,动作,科幻,剧情
《Lie to me》悬疑,警匪,动作,心理,剧情
《战狼2》战争,动作,灾难

将电影分类中的数组数据展开。结果如下:

《疑犯追踪》 悬疑

《疑犯追踪》 动作

《疑犯追踪》 科幻

《疑犯追踪》 剧情

《Lie to me》 悬疑

《Lie to me》 警匪

《Lie to me》 动作

《Lie to me》 心理

《Lie to me》 剧情

《战狼2》 战争

《战狼2》 动作

《战狼2》 灾难

解题:

  1. 创建hive表并导入数据,把category导入成array类型

    create table movie_info(
        movie string, 
        category array<string>) 
    row format delimited fields terminated by "\t"
    collection items terminated by ",";
    
    load data local inpath "/opt/module/datas/movie.txt" into table movie_info;
    
  2. 查询语句

    select 
    	movie, category_name
    from 
    	movie_info lateral view explode(category) table_tmp as category_name;
    
4. 窗口函数
  1. over:用 over 关键字就可以开一个窗口,其中可以指定窗口的范围,还可以指定分区和排序,如果指定了 order by,那么窗口范围是 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,如果没有指定 order by,那么窗口的范围是 ROW BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

    CURRENT ROW:当前行

    n PRECEDING:往前n行数据

    n FOLLOWING:往后n行数据

    UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点

  2. lag(col, n):往前第n行数据

  3. lead(col, n):往后第n行数据

  4. ntile(n):把有序分区中的行分发到指定数据的组中,每个组有编号,编号从1开始

  5. rank():

    rank():排名相同时会重复,总数不会变

    dense_rand():排名相同时会重复,总数会减少

    row_number():排名不重复

例1:

数据准备:

jack,2017-01-01,10

tony,2017-01-02,15

jack,2017-02-03,23

tony,2017-01-04,29

jack,2017-01-05,46

jack,2017-04-06,42

tony,2017-01-07,50

jack,2017-01-08,55

mart,2017-04-08,62

mart,2017-04-09,68

neil,2017-05-10,12

mart,2017-04-11,75

neil,2017-06-12,80

mart,2017-04-13,94

需求:

(1)查询在2017年4月份购买过的顾客及总人数

(2)查询顾客的购买明细及月购买总额

(3)上述的场景,要将cost按照日期进行累加

(4)查询顾客上次的购买时间

(5)查询前20%时间的订单信息

创建hive表并导入数据

create table business(
name string, 
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

load data local inpath "/opt/module/datas/business.txt" into table business;

(1)查询在2017年4月份购买过的顾客及总人数

select
	name,
	count(*) over()
from business
where substring(orderdate, 1, 7) = '2017-04'
group by name;

(2)查询顾客的购买明细及月购买总额

select 
	name,
	orderdate,
	cost,
	sum(cost) over(partition by month(orderdate))
from business;

(3)上述的场景,要将cost按照日期进行累加

select name,orderdate,cost, 
	sum(cost) over() as sample1,--所有行相加 
	sum(cost) over(partition by name) as sample2,--按name分组,组内数据相加 
	sum(cost) over(partition by name order by orderdate) as sample3,--按name分组,组内数据累加 
	sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row ) as sample4 ,--和sample3一样,由起点到当前行的聚合 
	sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and current row) as sample5, --当前行和前面一行做聚合 
	sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING ) as sample6,--当前行和前边一行及后面一行 
	sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --当前行及后面所有行 
from business;

(4)查询顾客上次购买的时间

select 
	name,
	orderdate,
	lag(orderdate, 1, '1900-01-01') over(partition by name order by orderdate)
from business;

(5)查询前20%时间的订单信息

select 
	*
from 
	(select 
		name, 
		orderdate,
		ntile(5) over(order by orderdate) sorted
	from business) t1
where sorted = 1;

例2:

数据准备

namesubjectscore
孙悟空语文87
孙悟空数学95
孙悟空英语68
大海语文94
大海数学56
大海英语84
宋宋语文64
宋宋数学86
宋宋英语84
婷婷语文65
婷婷数学85
婷婷英语78

需求

计算每门学科成绩排名。

创建hive表并导入数据

create table score(
name string,
subject string, 
score int) 
row format delimited fields terminated by "\t";
load data local inpath '/opt/module/datas/score.txt' into table score;

查询语句

select 
	name,
	subject,
	score,
	rank() over(partition by subject order by score desc),
	dense rank() over(partition by subject order by score desc) drp,
	row_number() over(partition by subject order by score desc) rmp
from score;

结果:

name subject score rp drp rmp

孙悟空 数学 95 1 1 1

宋宋 数学 86 2 2 2

婷婷 数学 85 3 3 3

大海 数学 56 4 4 4

宋宋 英语 84 1 1 1

大海 英语 84 1 1 2

婷婷 英语 78 3 2 3

孙悟空 英语 68 4 3 4

大海 语文 94 1 1 1

孙悟空 语文 87 2 2 2

婷婷 语文 65 3 3 3

宋宋 语文 64 4 4 4

七、存储和压缩

7.1 存储格式

1.行式存储和列式存储

在这里插入图片描述

​ (行式存储和列式存储)

行式存储:当查询满足条件的一整行数据时,行式存储的速度更快,因为列式存储需要去每个字段聚集的地方寻找对应的列,而行式存储只需要找到其中一个字段,其余字段都在附近的地方。

列式存储:因为每个字段都聚集存储,所以如果查询少数几个字段时,可以大大减少读取的数据量。

2. TextFile格式

​ TextFile每一行是一条记录,每行都以\n结尾。数据不做压缩,磁盘开销大,数据解析开销大。

3. SequenceFile格式

​ SequenceFile是Hadoop API提供的一种二进制文件支持,使用方便、可分割,可压缩。

4. Orc格式

​ Orc提供了一种将数据存储在hive表中的高效方法。该存储格式是为了克服其他存储格式的缺点而设计的,所以在hive中具有最高的性能,以及最小的存储空间。

5. Parquet格式

​ Parquet是一个面向列的二进制存储格式,是spark的默认存储格式,所以使用parquet可以极大地优化spark地调度和执行。

存储格式存储方式特点
TextFile行存储存储空间消耗比较大,并且压缩地text无法分割和合并,查询效率最低
SequenceFile行存储存储空间消耗最大,压缩地文件可以分割和合并,查询效率高
Orc行列结合,数据按行分块,每块按列存储存储空间消耗最小,查询效率最高
Parquet列存储相较于Orc,Parquet空间消耗较大,查询效率较低,但是在spark on hive的情况下,性能最好

7.2 压缩格式

1. 为什么使用压缩
  • 节省数据占用的磁盘空间
  • 加快数据在磁盘和网络中的传输速度,从而提高系统的处理速度
2. 常用压缩格式的对比
  • 特性对比

    压缩格式codec类算法扩展名多文件splitablenativehadoop自带
    deflateDeflateCodecdeflate.deflate
    gzipGzipCodecdeflate.gz
    bzip2Bzip2Codecbzip2.bz2
    lzoLzopCodeclzo.lzo
    snappySnappyCodecsnappy.snappy

    文件的可分割性在 Hadoop 中是很非常重要的,它会影响到在执行作业时 Map 启动的个数,从而会影响到作业的执行效率!

  • 性能对比

    压缩格式压缩比压缩速率解压速率
    gzip/deflate13.4%21MB/s118MB/s
    bzip213.2%2.4MB/s9.5MB/s
    lzo20.5%135MB/s410MB/s
    snappy22.2%172MB/s409MB/s
3. 使用情景
  • gzip
    • 当每个文件压缩之后在一个块大小内,可以考虑用gzip压缩格式。
  • bzip2
    • 对速度要求不高,但需要较高压缩率并且需要支持split的情况
  • lzo
    • 一个很大的文本文件,压缩之后还大于200M的可以考虑用lzo,而且单个文件越大,lzo的优点越明显
  • snappy
    • map输出的数据比较大的时候,作为map到reduce的中间数据压缩格式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值