文章目录
- 1、数据仓库的基本概念
- 2、数据仓库与数据库区别
- 3、数据仓库分层架构
- 4、为什么要对数据仓库分层?
- 5、Hive是什么
- 6、hive简述
- 8、用户接口:Client
- 9、SQL语言的分类
- 10、hive的几种表
- 11、hive的底层执行引擎有3种
- 12、分桶表
- 13、导入导出数据
- 14、having 与 where 不同点
- 15、4个By区别
- 16、hive的静态分区和动态分区
- 17、hive客户端jdbc操作
- 18、hive的可视化工具dbeaver
- 19、Hive参数配置方式
- 20、使用变量传递参数
- 21、hive的常用函数介绍
- 22、复合类型构建函数
- 23、lateral view 函数
- 24、reflect函数
- 25、hive当中的分析函数----分组求topN
- 26、hive自定义函数
- 27、hive当中如何创建永久函数
- 28、hive表的数据压缩
- 29、hive表的文件存储格式
- 30、hive的SerDe(序列与反序列化)
- 31、hive的企业级调优
1、数据仓库的基本概念
Data Warehouse,(DW或DWH)。
-
1、目的:
- 构建面向分析的集成化数据环境,为企业提供决策支持。它出于分析性报告和决策支持目的而创建。
- 数据仓库本身并不“生产”任何数据,同时自身也不需要“消费”任何的数据,数据来源于外部,并且开放给外部应用,这也是为什么叫“仓库”,而不叫“工厂”的原因。
- 面向主题:一般都是有一定的目的进行构建数据仓库
集成性:将所有用到的数据都会集成到一起去
非易失性:数据仓库里面的数据一般都不会改变(数据仓库是用于正确的记录已经发生的事实)
时变性:随着时间的发展,数据仓库分析的手段也会改变
-
2、主要特征:
-
面向主题:一般都是有一定的目的进行构建数据仓库
-
集成性:将所有用到的数据都会集成到一起去
-
非易失性:数据仓库里面的数据一般都不会改变(数据仓库是用于正确的记录已经发生的事实)
-
时变性:随着时间的发展,数据仓库分析的手段也会改变
-
2、数据仓库与数据库区别
一个是用于分析数据一个是用于保证事务性
数据仓库的出现不是要取代数据库,也不是一个大型的数据库的集合
(1)数据库是面向事务的设计,数据仓库是面向主题设计的。
(2)数据库一般存储业务数据,数据仓库存储的一般是历史数据。
(3)数据库是为捕获数据而设计,数据仓库是为分析数据而设计。
(3)数据库设计是尽量避免冗余,一般针对某一业务应用进行设计,比如一张简单的User表,记录用户名、密码等简单数据即可,符合业务应用,但是不符合分析。
数据仓库在设计是有意引入冗余,依照分析需求,分析维度、分析指标进行设计。
实际是联机事务处理 OLTP(On-Line Transaction Processing,)与 联机分析处理 OLAP(On-Line Analytical Processing) 的区别。
-
传统的数据库系统,作为数据管理的主要手段,主要用于操作型处理。
- 操作型处理,联机事务处理 OLTP,也可称面向交易的处理系统,
- 它是针对具体业务在数据库联机的日常操作,通常对少数记录进行查询、修改。
- 用户较为关心操作的响应时间、数据的安全性、完整性和并发支持的用户数等问题。
-
分析型处理,叫联机分析处理 OLAP,一般针对某些主题的历史数据进行分析,支持管理决策
-
数据仓库,是在数据库已经大量存在的情况下,为了进一步挖掘数据资源、为了决策需要而产生的,它决不是所谓的“大型数据库”。
3、数据仓库分层架构
-
(1)源数据层(ODS): 主要是用于保管我们的原始数据的
- 此层数据无任何更改,直接沿用外围系统数据结构和数据,不对外开放;为临时存储层,是接口数据的临时存储区域,为后一步的数据处理做准备。
-
(2)数据仓库层(DW):主要是用于面向数据分析的,大部分的工作,都是在这一层,写sql
- 也称为细节层,DW层的数据应该是一致的、准确的、干净的数据,即对源系统数据进行了清洗(去除了杂质)后的数据。
-
(3)数据应用层(DA或APP):主要用于数据的报表展示
- 前端应用直接读取的数据源;根据报表、专题分析需求而计算生成的数据。
ETL:数据仓库,从各数据源获取数据及在数据仓库内的数据,转换和流动都可以认为是ETL(抽取Extra, 转化Transfer, 装载Load)的过程,
ETL是数据仓库的流水线,也可以认为是数据仓库的血液,它维系着数据仓库中数据的新陈代谢,而数据仓库日常的管理和维护工作的大部分精力就是保持ETL的正常和稳定。
数据仓库的数据来源于不同的源数据,并提供多样的数据应用,数据自下而上流入数据仓库后向上层开放应用,而数据仓库只是中间集成化数据管理的一个平台。
4、为什么要对数据仓库分层?
-
用空间换时间,通过大量的预处理来提升应用系统的用户体验(效率),因此数据仓库会存在大量冗余的数据;
-
不分层的话,如果源业务系统的业务规则发生变化将会影响整个数据清洗过程,工作量巨大。
-
通过数据分层管理,可以简化数据清洗的过程,
- 因为把原来一步的工作分到了多个步骤去完成,相当于把一个复杂的工作拆成了多个简单的工作,把一个大的黑盒变成了一个白盒,每一层的处理逻辑都相对简单和容易理解,这样我们比较容易保证每一个步骤的正确性,当数据发生错误的时候,往往我们只需要局部调整某个步骤即可。
5、Hive是什么
-
Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。
-
本质是:将SQL转换为MapReduce任务进行运算,底层由HDFS来提供数据的存储,
-
说白了hive可以理解为一个将SQL转换为MapReduce的任务的工具,甚至更进一步可以说hive就是一个MapReduce的客户端
-
mr代码非常复杂的通过hive大大的简化了mr的开发,基本上hive可以解决90%的企业开发需求,hive就是mr的一个客户端,没有集群
-
底层的hadoop:数据存储hdfs,数据的计算mr,运行在yarn上面的
怎么把hive翻译成的mr的
主要就是通过解析器的,就是将sql语法解析成为mr的任务
解析器:主要就是用于解析sql语法
编译器:将解析之后的sql语法进行编译成为MR的任务
优化器:有一定的优化功能,自动的会对我们写的sql语句进行调优,调优的功能有限的
执行器:提交mr的任务到yarn上面去执行的
6、hive简述
- 大数据领域里面一个sql on hadoop的框架
- 主要的作用是:通过解析hql语句,实现hdfs上面的数据的查询操作
- 真实的数据保存在hdfs上面的,数据的计算,使用的mr的程序
- hive不提供数据的存储,也不提供数据的计算
- hive当中建库建表的元数据信息保存在mysql里面
- Hive 只适合用来做海量离线数据统计分析,也就是数据仓库
每执行一次查询,就会有对应的mr任务执行吗?
不一定的,有些查询,不需要mr的参与
hive优缺点:
-
优点
(1)操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手)。
(2)避免了去写MapReduce,减少开发人员的学习成本。
(3)Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
缺点
(1)Hive 不支持记录级别的增删改操作(2)Hive 的查询延迟很严重
(3)Hive 不支持事务
8、用户接口:Client
-
(1)CLI(hive shell):bin/hive
-
(2)JDBC/ODBC(java访问hive):
- 启动hiveserver2服务:
- bin/hive --service hiveserver2
- beeline连接hiveserver2
- bin/beeline
- beeline> !connect jdbc:hive2://node01:10000
- 启动hiveserver2服务:
-
(3)WEBUI(浏览器访问hive)
-
(4)hive 命令行
-
使用hive -e sql语句 来执行hql语句;
- bin/hive -e “show databases;” 不进入hive的客户端,直接执行hql语句
- 使用hive -f sql文件 执行hql文件
- bin/hive -f hive.sql 不进入hive的客户端,直接执行sql脚本文件
-
hive cli命令窗口查看本地文件系统
- 与操作本地文件系统类似,这里需要使用 ! (感叹号),并且最后需要加上 ;(分号) 。例如!ls /;
hive cli命令窗口查看HDFS文件系统
- 与查看HDFS文件系统类似 dfs -ls / ;
hive客户端jdbc操作
9、SQL语言的分类
SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL。
1. 数据查询语言DQL:SELECT子句,FROM子句,WHERE
2 .数据操纵语言DML:1) 插入:INSERT、2) 更新:UPDATE、3) 删除:DELETE
3. 数据定义语言DDL
来创建数据库中的各种对象-----表、视图、索引、同义词、聚簇等如:
CREATE TABLE/VIEW/INDEX/SYN/CLUSTER表 视图 索引 同义词 簇
DDL操作是隐性提交的!不能rollback
4. 数据控制语言DCL
用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等。如:
- GRANT:授权、2) ROLLBACK 回滚、3) COMMIT :提交。
10、hive的几种表
-
内部表:
- 创建内部表的时候,没有external关键字;
- 删除内部表的时候,会同步的删除hdfs的数据
-
外部表:
- 创建外部表的时候有external关键字;
- 删除外部表的时候,不会删除hdfs的数据
- 外部表删的只是表结构, 数据存在hdfs,元数据在mysql
-
分区表:
- 实际工作当中,数据一般都是按照每天进行采集的,每天的数据都会放到某一个日期文件夹,
- 分区表,就是分文件夹
-
分桶表:
- 直接对数据进行分桶,分成多个文件,每个文件里面保存部分数据,到时候如果需要获取数据的时候,可以直接从对应的文件里面获取即可
- 分桶将整个数据内容,按照某列属性值取hash值进行区分,具有相同hash值的数据进入到同一个文件中
- 可以过滤掉大量不相关的文件,提高查询效率
- 分桶表就是分文件,将一个大的文件分成多个小的文件,提高查询效率
外部表一般都是用在数据仓库的ODS层
内部表一般都是用在数据仓库的DW层
---数据定义语言DDL
--1、内部表:
use myhive;
create table stu(id int,name string);
insert into stu(id,name) values(1,"zhangsan");
select * from stu;
--2、外部表:
create external table score_stu (s_id string, c_id string,s_score int)
partitioned by (day string) row format delimited fields terminated by '\t'
location '/scoredatas'
--3、分区表:
create table score2 (s_id string,c_id string, s_score int)
partitioned by (year string,month string,day string)
row format delimited fields terminated by '\t';
--4、分桶表
create table myhive.user_buckets_demo(id int, name string)
clustered by(id) into 4 buckets
row format delimited fields terminated by '\t';
--表示按照id进行hashCode取值 % 4 确定每一条数据需要去到哪一个文件里面去
--就是前面的mr当中的分区的操
11、hive的底层执行引擎有3种
- mapreduce(默认)
- tez(支持DAG作业的计算框架)mr1–>mr2 -->mr3
- spark(基于内存的分布式计算框架)
12、分桶表
比较特殊,不能使用load,只能通过insert select方式加载数据
创建表的时候已经创建了文件夹,通过insert select的时候才创建文件
把文件传过去以后不用MSCK REPAIR TABLE吗?
- 不用,只有分区表需要修复,如果是个分区表,放到文件夹之后还得刷一下元数据
是不是可以在分区的基础上进行分桶?
- 对的,可以继续分桶的,内部分区分桶表 外部分区分桶表
- 分区分桶表:先对数据进行分文件夹,分了文件夹之后再进行划分桶
内部分区表 外部分区表 分区表需要load到对应的分区文件夹下面 然后 msck repair
内部表 外部表 都是可以load
13、导入导出数据
--数据操纵语言DML
--导入数据
--(1)直接导入
insert into table score3 partition(month ='201807') values ('001','002','100');
--(2)load方式
--load数据可以从,本地文件系统加载,或者也可以从hdfs上面的数据进行加载
load data local inpath '/kkb/install/hivedatas/teacher.csv' into table myhive.teacher;
load data inpath '/kkb/hdfsload/hivedatas' overwrite into table myhive.teacher;
--(3)查询导入 insert overwrite select
insert overwrite table score5 partition(month = '201806')
select s_id,c_id,s_score from score;
--(4)查询创建as select
create table score6 as select * from score;
--(5)location指定路径
create external table score7 (s_id string,c_id string,s_score int)
row format delimited fields terminated by '\t'
location '/myscore7';
--导出数据
--(1)insert查询导出
--查询导出本地 insert overwrite local director
insert overwrite local directory '/kkb/install/hivedatas/stu'
select * from stu;
--查询导出hdfs(无local) insert overwrite director
insert overwrite directory '/kkb/hivedatas/stu'
row format delimited fields terminated by ','
select * from stu;
--(2) Hive Shell 命令导出
bin/hive -e 'select * from myhive.stu;' > /kkb/install/hivedatas/student1.txt
--(3)export导出到HDFS
export table myhive.stu to '/kkb/install/hivedatas/stuexport';
数据操纵语言DML
插入一条数据,到表里面去,就是执行了一个mr的程序,生成了一个文件,文件里面就一条数据
--数据操纵语言DML
--alter
--#将stu内部表改为外部表
alter table stu set tblproperties('EXTERNAL'='TRUE');
--#把emp外部表改为内部表
alter table teacher set tblproperties('EXTERNAL'='FALSE');
--#修改表的名称
alter table stu3 rename to stu4;
--#增加列
alter table stu4 add columns(address string);
--数据查询语言DQL
-- select
select * from stu;
select id,name as stuName from stu; -- "as" 列改名
select count(*) cnt from score;
select max(s_score) from score; --- min(s_score) sum(s_score) avg(s_score)
select * from score limit 5;--limit子句用于限制返回的行数。
select * from score where s_score > 60;
--计算每个学生的平均分数 Group By 语句通常会和==聚合函数==一起使用
select s_id,avg(s_score) from score group by s_id;
--求每个学生平均分数大于60的人 having针对=查询结果中的列=发挥作用
select s_id,avg(s_score) as avgScore from score2
group by s_id having avgScore > 60;
--Hive支持通常的SQL JOIN语句,但是只支持等值连接,不支持非等值连接
--inner join(默认) left outer join right outer join full outer join
--根据学生和成绩表,查询学生姓名对应的成绩
select * from stu left join score on stu.id = score.s_id;
--按照学生分数的平均值排序
select s_id,avg(s_score) avgscore from score
group by s_id
order by avgscore desc; --全局排序,只有一个reduce asc默认升序
--条件函数
select if(1=2,100,200) from tableName;--200 if
select coalesce(null,'100','50') from tableName;--100 非空查找函数: COALESCE
--、条件判断函数:CASE
Select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end from tableName;
select case when 1=2 then 'tom' when 2=2 then 'mary' else 'tim' end from tableName;
14、having 与 where 不同点
- where针对==表中的列==发挥作用,查询数据;
- having针对==查询结果中的列==发挥作用,筛选数据
- where后面==不能写分组函数,而having后面可以使用分组函数==
- having只用于group by分组统计语句
15、4个By区别
1)Sort By:分区内有序;
2)Order By:全局排序,只有一个Reducer;
3)Distrbute By:类似MR中Partition,进行分区,结合sort by使用。
4) Cluster By:当Distribute by和Sorts by字段相同时,可以使用Cluster by方式。Cluster by除了具有Distribute by的功能外还兼具Sort by的功能。但是排序只能是升序排序,不能指定排序规则为ASC或者DESC。
-
1、Group By 分组
-
通常会和==聚合函数==一起使用,
-
按照一个或者多个列队结果进行分组,
-
然后对每个组执行聚合操作。
-
having只用于group by分组统计语句
-
--求每个学生平均分数大于60的人 select s_id,avg(s_score) as avgScore from score2 group by s_id having avgScore > 60;
-
-
2、order by 全局排序
-
只有一个reduce
-
asc 升序 (默认);desc 降序
-
order by 子句在select语句的结尾
-
--按照学生分数的平均值排序 select s_id,avg(s_score) avgscore from score group by s_id order by avgscore desc;
-
-
3、sort by 局部排序
-
每个reducer内部进行排序,对全局结果集来说不是排序
-
select * from score s sort by s.s_score;
-
-
4、distribute by 分区排序
-
指定按照哪个字段进行分区 可以自己控制分区的字段
-
类似MR中partition,采集hash算法,在map端将查询的结果中hash值相同的结果,分发到对应的reduce文件中。
-
distribute by语句要结合sort by使用,写在 sort by 语句之前
-
select * from score2 distribute by s_id sort by s_score;
-
-
5、cluster by = distribute by + sort by
-
当distribute by和sort by字段相同时,可以使用cluster by方式
-
除了distribute by 的功能外,还会对该字段进行排序,所以cluster by = distribute by + sort by
-
--以下两种写法等价 select * from score distribute by s_score sort by s_score; select * from score2 cluster by s_score;
-
16、hive的静态分区和动态分区
- 静态分区:表的分区字段的值,需要开发人员手动给定,通过查询的方式加载数据 ,必须要指定分区字段值
- 动态分区:按照需求,实现把数据自动导入到表的不同分区中,不需要手动指定
--创建普通表
create table t_order(
order_number string,
order_price double,
order_time string )
row format delimited fields terminated by '\t';
--创建目标分区表
create table order_dynamic_partition(
order_number string,
order_price double )
partitioned BY(order_time string)
row format delimited fields terminated by '\t';
--向普通表t_order加载数据
load data local inpath '/kkb/install/hivedatas/order_partition.txt'
overwrite into table t_order;
--要想进行动态分区,需要设置参数
//开启动态分区功能
hive> set hive.exec.dynamic.partition=true;
//设置hive为非严格模式
hive> set hive.exec.dynamic.partition.mode=nonstrict;
insert into table order_dynamic_partition partition(order_time)
select order_number,order_price,order_time from t_order;
--查看分区
show partitions order_dynamic_partition;
17、hive客户端jdbc操作
启动hiveserver2的服务端—引入依赖----代码开发
//获取数据库连接
Connection connection = DriverManager.getConnection(url, "hadoop","");
//定义查询的sql语句
String sql="select * from stu";
try {
PreparedStatement ps = connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while (rs.next()){
//获取id字段值
int id = rs.getInt(1);
//获取deptid字段
String name = rs.getString(2);
System.out.println(id+"\t"+name);
}
} catch (SQLException e) {
e.printStackTrace();
18、hive的可视化工具dbeaver
dbeaver是一个图形化的界面工具,专门用于与各种数据库的集成,通过dbeaver我们可以与各种数据库进行集成通过图形化界面的方式来操作我们的数据库与数据库表,类似于我们的sqlyog或者navicate
我们使用的版本是6.15这个版本,
19、Hive参数配置方式
Hive参数大全:
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
开发Hive应用时,不可避免地需要设定Hive的参数。
设定Hive的参数可以调优HQL代码的执行效率,或帮助定位问题。
对于一般参数,有以下三种设定方式:
- 配置文件 hive-site.xml
- 用户自定义配置文件:$HIVE_CONF_DIR/hive-site.xml
- 默认配置文件:$HIVE_CONF_DIR/hive-default.xml
- 用户自定义配置会覆盖默认配置。
- 命令行参数 启动hive客户端的时候可以设置参数
- 启动Hive(客户端或Server方式)时,可以在命令行添加-hiveconf param=value来设定参数,例如:
- bin/hive -hiveconf hive.root.logger=INFO,console
- 这一设定对本次启动的Session(对于Server方式启动,则是所有请求的Sessions)有效。
- 参数声明 进入客户单以后设置的一些参数 set
- 可以在HQL中使用SET关键字设定参数,例如:
- set mapred.reduce.tasks=100;
- 这一设定的作用域也是session级的。
参数声明 > 命令行参数 > 配置文件参数(hive)
20、使用变量传递参数
- 将hive的hql语法开发完成之后,就写入到一个脚本里面去,
- 然后定时的通过命令 hive -f 去执行hive的语法即可,
- 然后通过定义变量来传递参数到hive的脚本当中去,
hive0.9以及之前的版本是不支持传参的 hive1.0版本之后支持 hive -f 传递参数
一般使用 1、hivevar **2、hiveconf ** 来进行参数的传递
-
hivevar
- 用于定义HIVE运行时的变量替换
- 与${key}或者与 ${hivevar:key}配合使用
- bin/hive --hivevar name=zhangsan ${hivevar:name}
-
hiveconf
- 用于定义HIVE执行上下文的属性(配置参数),可覆盖覆盖hive-site.xml(hive-default.xml)中的参数值,
- hiveconf变量取值必须要使用hiveconf作为前缀参数,具体格式如下:
- bin/hive --hiveconf “mapred.job.queue.name=root.default”
select * from student
left join score on student.s_id = score.s_id
where score.month = '201807' and score.s_score > 80 and score.c_id = 03;
--定义hive脚本
vim hivevariable.hql
use myhive;
select * from student
left join score on student.s_id = score.s_id
where score.month = ${hiveconf:month} and score.s_score > ${hivevar:s_score} and score.c_id = ${c_id};
--调用hive脚本并传递参数
bin/hive --hiveconf month=201807 --hivevar s_score=80 --hivevar c_id=03 -f hivevariable.hql
21、hive的常用函数介绍
系统内置函数
hive> show functions; --1.查看系统自带的函数
hive> desc function upper; --2.显示自带的函数的用法
hive> desc function extended upper;--3.详细显示自带的函数的用法
select round(3.5) from tableName;
--取整函数: round 向下取整函数: floor 向上取整函数: ceil ceiling 取随机数函数: rand
--时间函数
select from_unixtime(1323308943,'yyyyMMdd') from tableName; ---20111208
--UNIX时间戳转日期函数: from_unixtime 日期时间转日期函数: to_date
select day('2011-12-08 10:03:01') from tableName;--8
--日期转年函数: year month day hour minute
select datediff('2012-12-08','2012-05-09') from tableName;--213
--日期转周函数: weekofyear 日期比较函数: datediff 日期增加函数: date_add 日期减少函数: date_sub
--字符串函数
select trim(' abc ') from tableName;--abc
--长度length 反转reverse 字符串连接concat 去空格trim 重复字符串repeat 分割: split
--转大写upper,ucase 转小写lower,lcase 字符串截取substr substring
--url解析parse_url json解析get_json_object
22、复合类型构建函数
- map
- 语法**: **map (key1, value1, key2, value2, …)
- 说明:根据输入的key和value,对构建map类型
- struct
- 语法: struct(val1, val2, val3, …)
- 说明:根据输入的参数构建结构体struct类型,似于C语言中的结构体,内部数据通过X.X来获取,
- array
- 语法: array(val1, val2, …)
- 说明:根据输入的参数构建数组array类型
23、lateral view 函数
- lateral view
- 用于和split、explode等UDTF一起使用的,能将一行数据拆分成多行数据,在此基础上可以对拆分的数据进行聚合,
- lateral view首先为原始表的每行调用UDTF,UDTF会把一行拆分成一行或者多行,
- lateral view再把结果组合,产生一个支持别名表的虚拟表。
- 其中explode还可以用于将hive一列中复杂的array或者map结构拆分成多行
Lateral View通常和UDTF一起出现,为了解决UDTF不允许在select字段的问题。
Multiple Lateral View可以实现类似笛卡尔乘积。
Outer关键字可以把不输出的UDTF的空结果,输出成NULL,防止丢失数据。
24、reflect函数
reflect函数,可以支持在sql中调用java中的自带函数,秒杀一切udf函数。
--使用java.lang.Math当中的Max,求两列中最大值
select reflect("java.lang.Math","max",col1,col2) from test_udf;
--使用apache commons中的函数,判断是否为数字
select reflect("org.apache.commons.lang.math.NumberUtils","isNumber","123");
25、hive当中的分析函数----分组求topN
对于一些比较复杂的数据求取过程,我们可能就要用到分析函数,分析函数主要用于分组求topN,或者求取百分比,或者进行数据的切片等等,我们都可以使用分析函数来解决
常用的分析函数介绍
- 1、ROW_NUMBER():
- 从1开始,按照顺序,生成分组内记录的序列,比如,按照pv降序排列,生成分组内每天的pv名次,ROW_NUMBER()的应用场景非常多,再比如,获取分组内排序第一的记录;获取一个session中的第一条refer等。
- 2、RANK() :
- 生成数据项在分组中的排名,排名相等会在名次中留下空位
- 3、DENSE_RANK() :
- 生成数据项在分组中的排名,排名相等会在名次中不会留下空位
- 4、CUME_DIST :
- 小于等于当前值的行数/分组内总行数。比如,统计小于等于当前薪水的人数,所占总人数的比例
- 5、PERCENT_RANK :
- 分组内当前行的RANK值/分组内总行数
- 6、NTILE(n) :
- 用于将分组数据按照顺序切分成n片,返回当前切片值,如果切片不均匀,默认增加第一个切片的分布。NTILE不支持ROWS BETWEEN,比如 NTILE(2) OVER(PARTITION BY cookieid ORDER BY createtime ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)。
26、hive自定义函数
Hive 自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便的扩展。
根据用户自定义函数类别分为以下三种:
(1)UDF(User-Defined-Function) 一进一出
(2)UDAF(User-Defined Aggregation Function) 聚集函数,多进一出 类似于:count/max/min
(3)UDTF(User-Defined Table-Generating Functions)一进多出 如lateral view explode()
编程步骤:
-
(1)继承org.apache.hadoop.hive.ql.UDF
-
(2)需要实现evaluate函数;evaluate函数支持重载;
-
注意事项
-
(1)UDF必须要有返回类型,可以返回null,但是返回类型不能为void;
-
(2)UDF中常用Text/LongWritable等类型,不推荐使用java类型;
27、hive当中如何创建永久函数
在hive当中添加临时函数,需要我们每次进入hive客户端的时候都需要添加以下,
退出hive客户端临时函数就会失效,那么我们也可以创建永久函数来让其不会失效
创建永久函数,与我们的函数进行关联
create function myuppercase as ‘com.kkb.udf.MyUDF’;
1、指定数据库,将我们的函数创建到指定的数据库下面
0: jdbc:hive2://node03:10000>use myhive;
2、使用add jar添加我们的jar包到hive当中来
0: jdbc:hive2://node03:10000>add jar /kkb/install/hive-1.1.0-cdh5.14.2/lib/udf.jar;
3、查看我们添加的所有的jar包
0: jdbc:hive2://node03:10000>list jars;
4、创建永久函数,与我们的函数进行关联
0: jdbc:hive2://node03:10000>create function myuppercase as 'com.kkb.udf.MyUDF';
5、查看我们的永久函数
0: jdbc:hive2://node03:10000>show functions like 'my*';
6、使用永久函数
0: jdbc:hive2://node03:10000>select myhive.myuppercase('helloworld');
7、删除永久函数
0: jdbc:hive2://node03:10000>drop function myhive.myuppercase;
8、查看函数
show functions like 'my*';
28、hive表的数据压缩
-
压缩模式评价
- 可使用以下三种标准对压缩方式进行评价
- 1、压缩比:压缩比越高,压缩后文件越小,所以压缩比越高越好
- 2、压缩时间:越快越好
- 3、已经压缩的格式文件是否可以再分割:可以分割的格式允许单一文件由多个Mapper程序处理,可以更好的并行化
- 可使用以下三种标准对压缩方式进行评价
-
常见压缩格式
压缩方式 | 压缩比 | 压缩速度 | 解压缩速度 | 是否可分割 |
---|---|---|---|---|
gzip | 13.4% | 21 MB/s | 118 MB/s | 否 |
bzip2 | 13.2% | 2.4MB/s | 9.5MB/s | 是 |
lzo | 20.5% | 135 MB/s | 410 MB/s | 是 |
snappy | 22.2% | 172 MB/s | 409 MB/s | 否 |
- Hadoop编码/解码器方式
压缩格式 | 对应的编码/解码器 |
---|---|
DEFLATE | org.apache.hadoop.io.compress.DefaultCodec |
Gzip | org.apache.hadoop.io.compress.GzipCodec |
BZip2 | org.apache.hadoop.io.compress.BZip2Codec |
LZO | com.hadoop.compress.lzo.LzopCodec |
Snappy | org.apache.hadoop.io.compress.SnappyCodec |
压缩性能的比较
压缩算法 | 原始文件大小 | 压缩文件大小 | 压缩速度 | 解压速度 |
---|---|---|---|---|
gzip | 8.3GB | 1.8GB | 17.5MB/s | 58MB/s |
bzip2 | 8.3GB | 1.1GB | 2.4MB/s | 9.5MB/s |
LZO | 8.3GB | 2.9GB | 49.3MB/s | 74.6MB/s |
-
开启map输出阶段压缩
- 可以减少job中map和Reduce task间数据传输量。具体配置如下:
-
开启Reduce输出阶段压缩
-
当Hive将输出写入到表中时,输出内容同样可以进行压缩。属性hive.exec.compress.output控制着这个功能。用户可能需要保持默认设置文件中的默认值false,这样默认的输出就是非压缩的纯文本文件了。用户可以通过在查询语句或执行脚本中设置这个值为true,来开启输出结果压缩功能。
29、hive表的文件存储格式
-
Hive支持的存储数的格式主要有:
- 行式存储: TEXTFILE、SEQUENCEFILE
- 列式存储:ORC、PARQUET
-
行存储
- 查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。select *
-
列存储
- 因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。 select 某些字段效率更高
TEXTFILE 和 SEQUENCEFILE:的存储格式都是基于行存储的;
ORC 和 PARQUET:是基于列式存储的。
30、hive的SerDe(序列与反序列化)
Serde是 Serializer/Deserializer的简写。
hive使用Serde进行行对象的序列与反序列化。最后实现把文件内容映射到 hive 表中的字段数据类型。
Hive 是如何读数据的(类似于 HDFS 中数据的读写操作):
HDFS files –> InputFileFormat –> <key, value> –> Deserializer –> Row object
Row object –> Serializer –> <key, value> –> OutputFileFormat –> HDFS files
hive的SerDe 类型
- 创建表时 使用row format 参数说明SerDe的类型。
- 如果 ROW FORMAT没有指定或者指定了 ROW FORMAT DELIMITED,就会使用native Serde。
- Hive SerDes:
- Avro (Hive 0.9.1 and later)
- ORC (Hive 0.11 and later)
- RegEx
- Thrift
- Parquet (Hive 0.13 and later)
- CSV (Hive 0.14 and later)
- MultiDelimitSerDe
--通过RegexSerDe 解决多字符分割场景(正则)
create table t2(id int, name string)
row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe' --正则
WITH SERDEPROPERTIES ("input.regex" = "^(.*)\\#\\#(.*)$");
-- 通过MultiDelimitSerDe ==解决多字符分割场景==
create table t1 (id String, name string)
row format serde 'org.apache.hadoop.hive.contrib.serde2.MultiDelimitSerDe'
WITH SERDEPROPERTIES ("field.delim"="##");
31、hive的企业级调优
-
1. Fetch抓取:让一些hql语句不用执行MR程序
- Fetch抓取是指,对某些情况的查询可以不必使用MapReduce计算
- 配置:hive-default.xml.template文件中 hive.fetch.task.conversion默认是more
- 老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。
- 把 hive.fetch.task.conversion设置成none,然后执行查询语句,都会执行mapreduce程序
- 把hive.fetch.task.conversion设置成more,然后执行查询语句,查询方式都不会执行mr程序
-
2. 本地模式:如果数据量小,只启动一个Maptask
- 在Hive客户端测试时,默认情况下是启用hadoop的job模式,把任务提交到集群中运行,这样会导致计算非常缓慢;
- Hive可以通过本地模式在单台机器上处理任务。对于小数据集,执行时间可以明显被缩短。
- 配置:开启本地模式,并执行查询语句
set hive.exec.mode.local.auto=true; //开启本地mr
-
3. 表的优化
- **大小表 join 时,小表放在join的左边 ** 老版本hive
- 将key相对分散 且 数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率;
- 新版hive已经优化,小表放在左边和右边已经没有明显区别。
- 多个表关联时,最好分拆成小段,避免大sql(无法控制中间Job)
- 大表 join 大表 时,空 key 赋一个随机的值
- key 为空对应的数据很多,但相应的数据不是异常数据,某些key对应的数据太多,而相同key对应的数据都会发送到相同的reducer上,从而导致内存不够。
- 方法:将 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。
- 用 MapJoin ,把小表全部加载到内存,在map端进行join,避免reducer处理。
- 如果不指定MapJoin 或者不符合 MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段完成join,容易发生数据倾斜。
- 配置:set hive.auto.convert.join = true;
- 在Map端先进行部分聚合,最后在Reduce端得出最终结果
- Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了。
- count distinct使用先group by 再count的方式替换
- 数据量大的情况下,由于count distinct 操作需要用一个reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,
- 避免笛卡尔积,即避免join的时候不加on条件,或者无效的on条件
- Hive只能使用1个reducer来完成笛卡尔积。
-
4.使用分区剪裁、列剪裁
- 尽可能早地过滤掉尽可能多的数据量,避免大量数据流入外层SQL。
- 列剪裁
- 只获取需要的列的数据,减少数据输入。
- 分区裁剪
- 分区在hive实质上是目录,分区裁剪可以方便直接地过滤掉大部分数据。
- 尽量使用分区过滤,少用select *
-
5. 并行执行
- 把一个sql语句中没有相互依赖的阶段,并行去运行,提高集群资源利用率
- 配置:set hive.exec.parallel=true; set hive.exec.parallel.thread.number=16;
-
6. 严格模式
- 防止用户执行,那些可能意想不到的不好的影响的查询。
- 配置:set hive.mapred.mode=strict; 默认是非严格模式nonstrict
- 开启严格模式可以禁止3种类型的查询。
- 对eizpw于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行
- 对于使用了order by语句的查询,要求必须使用limit语句
- 限制笛卡尔积的查询
-
7.JVM重用
- 对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。
- Hadoop的默认配置通常是,使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况。
- JVM重用可以,使得JVM实例在同一个job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间,具体多少需要根据具体业务场景测试得出。
-
8.开启推测执行机制,(Speculative Execution)
- 根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果
-
9.数据的压缩
- Hive表中间数据压缩
- Hive表最终输出结果压缩
-
10.避免数据倾斜
-
1 合理设置Map数
-
- 通常情况下,作业会通过input的目录产生一个或者多个map任务。
主要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小。
-
2) 是不是map数越多越好?不是
如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。
-
3) 是不是保证每个map处理接近128m的文件块,就高枕无忧了?不一定
比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
-
针对上面的问题2和3,我们需要采取两种方式来解决:即减少map数和增加map数;
-
-
2 小文件合并
-
在map执行前合并小文件,减少map数:
-
CombineHiveInputFormat 具有对小文件进行合并的功能(系统默认的格式)
-
-
3 复杂文件增加Map数
- 当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
- 增加map的方法为
- 根据 ==computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))==公式
- 调整maxSize最大值。让maxSize最大值低于blocksize就可以增加map的个数。
-
4 合理设置Reduce数
-
调整reduce个数 方法一
- 1)每个Reduce处理的数据量默认是256MB set hive.exec.reducers.bytes.per.reducer=256000000;
-
- 每个任务最大的reduce数,默认为1009 set hive.exec.reducers.max=1009;
-
- 计算reducer数的公式 N=min(参数2,总输入数据量/参数1)
-
调整reduce个数 方法二
- –设置每一个job中reduce个数
set mapreduce.job.reduces=3;
- –设置每一个job中reduce个数
-
reduce个数并不是越多越好
- 过多的启动和初始化reduce也会消耗时间和资源;
-
-
理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。
- 3) 是不是保证每个map处理接近128m的文件块,就高枕无忧了?不一定
比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
- 针对上面的问题2和3,我们需要采取两种方式来解决:即减少map数和增加map数;
-
2 小文件合并
-
在map执行前合并小文件,减少map数:
-
CombineHiveInputFormat 具有对小文件进行合并的功能(系统默认的格式)
-
-
3 复杂文件增加Map数
- 当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
- 增加map的方法为
- 根据 ==computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))==公式
- 调整maxSize最大值。让maxSize最大值低于blocksize就可以增加map的个数。
-
4 合理设置Reduce数
-
调整reduce个数 方法一
- 1)每个Reduce处理的数据量默认是256MB set hive.exec.reducers.bytes.per.reducer=256000000;
-
- 每个任务最大的reduce数,默认为1009 set hive.exec.reducers.max=1009;
-
- 计算reducer数的公式 N=min(参数2,总输入数据量/参数1)
-
调整reduce个数 方法二
- –设置每一个job中reduce个数
set mapreduce.job.reduces=3;
- –设置每一个job中reduce个数
-
reduce个数并不是越多越好
-
过多的启动和初始化reduce也会消耗时间和资源;
-
同时过多的reduce会生成很多个文件,也有可能出现小文件问题
-
-