Apache-Hive实践
数据类型
基本数据类型
集合数据类型
STRUCT:例如: address struct<street:string, city:string> 可以通过address.street 来访问
ARRAY:例如:friends array
可以通过 friend[index] 来访问 MAP:例如:children map<string, int>, 可以通过children[key]来访问
类型的转换
INT不会自动转换为TINYINT类型,它会返回错误,除非使用CAST操作
任何整数类型都可以隐式地转换为一个范围更广的类型,如TINYINT可以转换成INT,INT可以转换成BIGINT。
所有整数类型、FLOAT和STRING类型都可以隐式地转换成DOUBLE。
TINYINT、SMALLINT、INT都可以转换为FLOAT。
BOOLEAN类型不可以转换为任何其它的类型
1 | //一行数据如下 |
1 | #建表语句 |
1 | txt数据与导入hive的语句 |
1 | #查询语句和结果 |
DDL 数据定义语言详解
库
- 数据库创建的标准语法
1 | create database if not exists db_demo1; |
- 查询数据库的语法
1 | #1.显示 支持模糊查询 |
修改数据库的语法与注意事项
用户可以使用
ALTER DATABASE
命令为某个数据库的DBPROPERTIES
设置键-值对属性值,来描述这个数据库的属性信息。数据库的其他元数据信息都是不可更改的,包括数据库名和数据库所在的目录位置。
1 | alter database db_demo1 set dbproperties('createtime'='20201114'); |
- 删除数据库的标准语法
1 | #删除 |
表
建表语法的描述
CREATE TABLE:建表
EXTERNA:外部表
COMMENT:为表和列添加注释
PARTITIONED BY:分区
CLUSTERED BY:分桶
SORTED BY:
ROW FORMAT:在建表的时候可以自定义SerDe或者使用自带的SerDe
STORED AS :设置存储的类型
LOCATION :指定表在HDFS上的存储位置
LIKE:复制现有表的结构,但不复制内容
1 | #普通建表 |
- 内部表和外部表
默认创建的表都是所谓的管理表,有时也被称为内部表,当我们删除一个管理表时,Hive也会删除这个表中数据。管理表不适合和其他工具共享数据
表是外部表,所以Hive并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉
删除内部表会直接删除元数据(metadata)及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除;
对内部表的修改会将修改直接同步给元数据,而对外部表的表结构和分区进行修改,则需要修复(MSCK REPAIR TABLE
table_name;)适用的场合:每天将收集到的网站日志定期流入HDFS文本文件。在外部表(原始日志表)的基础上做大量的统计分析,用到的中间表、结果表使用内部表存储,数据通过SELECT+INSERT进入内部表。
1 | #内部表和外部表的转换 |
分区表
概念
分区表实际上就是对应一个HDFS文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。Hive中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过WHERE子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。
查询时Hive自动过滤掉不用于提高性能的分区
分为静态分区和动态分区
操作 (一级分区、二级分区、)
1 | #没有分区 |
- 修改表和删除表
1 | #重命名 |
DML 数据操纵语言详解
数据导入
1 | #向表中装载数据 |
数据导出
1 | #查询结果导入到本地 |
DQL 数据查询语言详解
基本查询
常用函数
算术运算符
Limit
空值的处理
1 | # count( ) count(*) 区别 |
where语句
between and
in is null exist
like rlike
- % 代表零个或多个字符(任意个字符)。
- _ 代表一个字符。
- rlike支持正则表达式
逻辑运算符
分组查询
group by
having
join连接
Hive支持通常的SQL JOIN语句,但是只支持等值连接,不支持非等值连接
join连接谓词中不支持or
基础SQL案例
1 | #SQL互联网50题hive实现 |
排序语法
全局排序(order by )
Order By:全局排序,一个Reducer
ASC(ascend): 升序(默认)
DESC(descend): 降序
每个MapReduce内部排序(Sort By)
set mapreduce.job.reduces=3;(设置reduce数目)
set mapreduce.job.reduces;(查看reduce数目)
分区排序(Distribute By)
类似MR中partition,进行分区,结合sort by使用
Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前
要分配多reduce进行处理,否则无法看到distribute by的效果。
Cluster By
当distribute by和sorts by字段相同时,可以使用cluster by方式。
cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是升序排序,不能指定排序规则为ASC或者DESC。
分桶与抽样查询
概念:
分区针对的是数据的存储路径;分桶针对的是数据文件,
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区,特别是之前所提到过的要确定合适的划分大小这个疑虑
分桶对数据的处理比分区更加细粒度化;
分桶和分区两者不干扰,可以把分区表进一步分桶;
1 |
|
- 分桶抽样查询
1 | #示例 |
动态分区和静态分区详解
首先是要创建静态分区表;然后将表设置为非严格模式;再次创建动态分区表,并加载数据。
加载数据的时候,是按照静态分区的模式,将数据加载到动态分区中去。
注意事项要开启yarn不然报错:org.apache.hadoop.hive.ql.exec.mr.MapRedTask
1 | #案例 |
窗口函数总结
窗口函数
1 | #窗口函数的语法 |
- 偏移量函数:lag lead
lag(列名,往前的行数,[行数为null时的默认值,不指定为null]),可以计算用户上次购买时间,或者用户下次购买时间。
lead(列名,往后的行数,[行数为null时的默认值,不指定为null])
- first_value 和 last_value
first_value取分组内排序后,截止到当前行,第一个值
last_value取分组内排序后,截止到当前行,最后一个值
1 | #sql |
序列函数
rank():1,2,2,2,5,6
dense_rank():1,2,2,3,4,4,5
row_number():1,2,3,4,5,6
ntile(n):用于将分组数据按照顺序切分成n片,返回当前切片值
1 | #ntile(n) 支持over() |
控制窗口大小的使用
PRECEDING:往前
FOLLOWING:往后
CURRENT ROW:当前行
UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING:表示到后面的终点
1 | #例如 |
SQL习题-窗口函数
topN案例
1 | #SQL |
连续登陆案例
1 | #sql |
基础SQL案例
1 | #SQL |
列转行、行转列
列转行
- 函数的说明:
- CONCAT(STRING A ,STRINFG B):返回字符串的连接后的结果
- CONCAT_WS(separator, str1, str2,…):这是一个特殊的CONCAT(),第一个参数是分隔符
- COLLECT_SET():函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段
- CONCAT_WS(SEPARATOR ,COLLECT_SET(column)) ===>GROUP_CONCAT()函数
1 | #SQL |
行转列
- 函数的说明
- EXPLODE(col):将hive一列中复杂的array或者map结构拆分成多行。
- LATERAL VIEW:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合
- split(str , 分隔符):返回一个数组
1 | #SQL |
case when语法、if语法
case when的语法
- CASE 字段 WHEN 值1 THEN 值1 [WHEN 值2 THEN 值2] [ELSE 值] END
- CASE WHEN 条件表达式 THEN 值1 [WHEN 条件表达式 [and or] 条件表达式THEN 值2] [ELSE 值] END
if的语法
- if( , , )
1 | #SQL |
基础SQL案例
1 | #SQL |
内置函数集合
数学函数
字符函数
substr()
substr(a,b):从字符串a中,第b位开始取,取右边所有的字符
substr(a,b,c):从字符串a中,第b为开始取,取c个字符,b可为负数从后面数
填充
lpad(左填充)rpad(右填充)
例如:select lpad(‘abc’,10,’‘); 往左填充10个\
集合函数
- str_to_map(‘a:1,b:2,c:3’);字符串转map
- select size(str_to_map(‘a:1,b:2,c:3’));返回map的元素个数
- map_keys(str_to_map(‘a:1,b:2’));返回key
转换函数
- cast():select cast(‘2018-06-28’ as date);字符串转日期类型
日期函数
- unix_timestamp() 日期转换为当前时间戳
- from_unixtime(t1,yyyy-MM-dd HH:mm:ss)时间戳转变为日期格式
- from_unixtime(unix_timestamp(date_created),yyyy-MM-dd HH:mm:ss)来规范时间的格式
Hive自定义函数详解
(UDF、UDAF、UDTF)
MACRO (宏) 的使用
执行流程分析
优化策略
常用优化策略
- 减少job数量
- 数据量较大的情况下,慎用 count(distinct),group by 容易产生倾斜问题
- 合并小文件
- 解决数据倾斜
笛卡尔积与MapJoin的使用
怎么写in、exists
- hive 的一个高效替代方案:left semi join
小文件的合并
1 | #常用设置 |
解决小文件过多的方案
产生小文件的来源和影响
- 来源
- 源数据本身有很多小文件
- 动态分区会产生大量小文件
- reduce个数越多, 小文件越多
- 按分区插入数据的时候会产生大量的小文件, 文件个数 = maptask个数 * 分区数
- 影响
- 从Hive的角度看,小文件会开很多map,一个map开一个JVM去执行,所以这些任务的初始化,启动,执行会浪费大量的资源,严重影响性能。
- HDFS存储太多小文件, 会导致namenode元数据特别大, 占用太多内存, 制约了集群的扩展。
解决的方法
- 调参进行合并
1 | #每个Map最大输入大小(这个值决定了合并后文件的数量) |
- distribute by rand() 将数据随机分配给 reduce
1 | # 设置每个reducer处理的大小为5个G |
- sequencefile 作为表存储格式,不要用 textfile,在一定程度上可以减少小文件
- 使用hadoop的archive归档
1 | #用来控制归档是否可用 |
- hadoop自带的三种小文件处理方案
电子商务消费行为分析(未找到数据)
1 | #数据与需求 |
textfile、sequencefile 和 rcfile
文件存储编码格式 | 建表时如何指定 | 优点弊端 | |
---|---|---|---|
textfile | 文件存储就是正常的文本格式,将表中的数据在hdfs上 以文本的格式存储,下载后可以直接查看,也可以使用cat命令查看 | 1.无需指定,默认2.显示指定stored as textfile | 1. 行存储使用textfile存储文件默认每一行就是一条记录,2.可以使用任意的分隔符进行分割。3.但无压缩,所以造成存储空间大。可结合Gzip、Bzip2、Snappy等使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。3.但无压缩,所以造成存储空间大。可结合Gzip、Bzip2、Snappy等使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。 |
sequencefile | 在hdfs上将表中的数据以二进制格式编码,并且将数据压缩了,下载数据以后是二进制格式,不可以直接查看,无法可视化。 | 1.stored as sequecefile | 1.sequencefile存储格有压缩,存储空间小,有利于优化磁盘和I/O性能2.同时支持文件切割分片,提供了三种压缩方式:none,record,block(块级别压缩效率跟高).默认是record(记录) |
rcfile | 在hdfs上将表中的数据以二进制格式编码,并且支持压缩。下载后的数据不可以直接可视化。 | 1.stored as rcfile | 1.行列混合的存储格式,基于列存储。 |
面试题摘要
1 | #SQL |
//SQL实现dense_rank()排序,sum()的窗口的实现