一、Hive是什么
1、Hive的概念
Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。其本质是将SQL转换为MapReduce的任务进行运算,底层由HDFS来提供数据的存储,说白了hive可以理解为一个将SQL转换为MapReduce的任务的工具,甚至更进一步可以说hive就是一个MapReduce的客户端
2、Hive与数据库的区别
- Hive 具有 SQL 数据库的外表,但应用场景完全不同。
- Hive 只适合用来做海量离线数据统计分析,也就是数据仓库。
3、Hive的优缺点
- 优点
- 操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手)。
- 避免了去写MapReduce,减少开发人员的学习成本。
- Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
- 缺点
- Hive 不支持记录级别的增删改操作
- Hive 的查询延迟很严重
- hadoop jar xxxx.jar xxx.class /input /output
- 进行任务的划分,然后进行计算资源的申请
- map 0% reduce 0%
- map 10% reduce 0%
- Hive 不支持事务
4、Hive架构原理
- 1、用户接口:Client
- CLI(hive shell)、JDBC/ODBC(java访问hive)、WEBUI(浏览器访问hive)
- 2、元数据:Metastore
- 元数据包括:表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;
- 默认存储在自带的derby数据库中,==推荐使用MySQL存储Metastore==
- 3、Hadoop集群
- 使用HDFS进行存储,使用MapReduce进行计算。
- 4、Driver:驱动器
- 解析器(SQL Parser)
- 将SQL字符串转换成抽象语法树AST
- 对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误
- 编译器(Physical Plan):将AST编译生成逻辑执行计划
- 优化器(Query Optimizer):对逻辑执行计划进行优化
- 执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于Hive来说默认就是mapreduce任务
二、Hive交互方式
先启动hadoop集群和mysql服务
1、Hive交互shell
cd /kkb/install/hive-1.1.0-cdh5.14.2
bin/hive
2、Hive JDBC服务
- 启动hiveserver2服务
- 前台启动
cd /kkb/install/hive-1.1.0-cdh5.14.2
bin/hive --service hiveserver2
- 后台启动
cd /kkb/install/hive-1.1.0-cdh5.14.2
nohup bin/hive --service hiveserver2 &
- beeline连接hiveserver2
重新开启一个会话窗口,然后使用beeline连接hive
cd /kkb/install/hive-1.1.0-cdh5.14.2
bin/beeline
beeline> !connect jdbc:hive2://node03:10000
3、Hive的命令
- hive -e sql语句
- 使用 –e 参数来直接执行hql的语句
cd /kkb/install/hive-1.1.0-cdh5.14.2/
bin/hive -e "show databases"
- hive -f sql文件
- 使用 –f 参数执行包含hql语句的文件
- node03执行以下命令准备hive执行脚本
cd /kkb/install/
vim hive.sql
文件内容如下
create database if not exists myhive;
通过以下命令来执行我们的hive脚本
cd /kkb/install/hive-1.1.0-cdh5.14.2/
bin/hive -f /kkb/install/hive.sql
三、Hive数据类型
1、基本数据类型
类型名称 | 描述 | 举例 |
boolean | true/false | true |
tinyint | 1字节的有符号整数 | 1 |
smallint | 2字节的有符号整数 | 1 |
int | 4字节的有符号整数 | 1 |
bigint | 8字节的有符号整数 | 1 |
float | 4字节单精度浮点数 | 1.0 |
double | 8字节单精度浮点数 | 1.0 |
string | 字符串(不设长度) | “abc” |
varchar | 字符串(1-65355长度,超长截断) | “abc” |
timestamp | 时间戳 | 1563157873 |
date | 日期 | 20190715 |
2、复合数据类型
类型名称 | 描述 | 举例 |
array | 一组有序的字段,字段类型必须相同 array(元素1,元素2) | Array(1,2,3) |
map | 一组无序的键值对 map(k1,v1,k2,v2) | Map(‘a’,1,'b',2) |
struct | 一组命名的字段,字段类型可以不同 struct(元素1,元素2) | Struct('a',1,2,0) |
- array字段的元素访问方式:
- 下标获取元素,下标从0开始
- 获取第一个元素
- array[0]
- map字段的元素访问方式
- 通过键获取值
- 获取a这个key对应的value
- map['a']
- struct字段的元素获取方式
- 定义一个字段c的类型为struct{a int;b string}
- 获取a和b的值
- 使用c.a 和c.b 获取其中的元素值
- 这里可以把这种类型看成是一个对象
create table complex(
col1 array<int>,
col2 map<string,int>,
col3 struct<a:string,b:int,c:double>
)
四、Hive的DDL操作
1、Hive的数据库DDL操作
1.1、创建数据库
hive > create database db_hive;
# 或者
hive > create database if not exists db_hive;
数据库在HDFS上的默认存储路径是/user/hive/warehouse/*.db
1.2、显示所有数据库
hive> show databases;
1.3、查询数据库
hive> show databases like 'db_hive*';
1.4、查看数据库详情
hive> desc database db_hive;
1.5、显示数据库详细信息
hive> desc database extended db_hive;
1.6、切换当前数据库
hive > use db_hive;
1.7、删除数据库
#删除为空的数据库
hive> drop database db_hive;
#如果删除的数据库不存在,最好采用if exists 判断数据库是否存在
hive> drop database if exists db_hive;
#如果数据库中有表存在,这里需要使用cascade强制删除数据库
hive> drop database if exists db_hive cascade;
2、Hive的数据表DDL操作
2.1、建表语法介绍
官网地址:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL
五、Hive数据导入
1、通过load方式加载数据
hive> load data [local] inpath 'dataPath' overwrite | into table student [partition (partcol1=val1,…)];
hive (myhive)> load data local inpath '/kkb/install/hivedatas/score.csv' overwrite into table score3 partition(month='201806');
2、通过查询方式加载数据
hive (myhive)> create table score5 like score;
hive (myhive)> insert overwrite table score5 partition(month = '201806') select s_id,c_id,s_score from score;
3、查询语句中创建表并加载数据(as select)
hive (myhive)> create table score6 as select * from score;
4、创建表时通过location指定加载数据路径
1)创建表,并指定在hdfs上的位置
hive (myhive)> create external table score7 (s_id string,c_id string,s_score int)
row format delimited fields terminated by '\t'
location '/myscore7';
2)上传数据到hdfs上,我们也可以直接在hive客户端下面通过dfs命令来进行操作hdfs的数据
hive (myhive)> dfs -mkdir -p /myscore7;
hive (myhive)> dfs -put /kkb/install/hivedatas/score.csv /myscore7;
3)查询数据
hive (myhive)> select * from score7;
5、export导出与import导入hive表数据(内部表操作)
hive (myhive)> create table teacher2 like teacher;
hive (myhive)> export table teacher to '/kkb/teacher';
hive (myhive)> import table teacher2 from '/kkb/teacher';
六、Hive数据导出
1、insert导出
1、将查询的结果导出到本地
insert overwrite local directory '/kkb/install/hivedatas/stu' select * from stu;
2、将查询的结果格式化导出到本地
insert overwrite local directory '/kkb/install/hivedatas/stu2'
row format delimited fields terminated by ','
select * from stu;
3、将查询的结果导出到HDFS上(没有local)
insert overwrite directory '/kkb/hivedatas/stu'
row format delimited fields terminated by ','
select * from stu;
2、Hive shell 命令导出
基本语法:
- hive -e "sql语句" > file
- hive -f sql文件 > file
bin/hive -e 'select * from myhive.stu;' > /kkb/install/hivedatas/student1.txt
3、export导出到HDFS上
export table myhive.stu to '/kkb/install/hivedatas/stuexport';
七、Hive的基本查询语法
1、基本查询
注意
- SQL 语言大小写不敏感
- SQL 可以写在一行或者多行
- 关键字不能被缩写也不能分行
- 各子句一般要分行写
- 使用缩进提高语句的可读性
1.1、全表和特定查询
全表查询
select * from stu;
查询特定列
select id,name from stu;
1.2、列起别名
- 重命名一个列
- 紧跟列名,也可以在列名和别名之间加入关键字 ‘as’
- 案例实操
select id,name as stuName from stu;
1.3、常用函数
1.求总行数(count)
select count(*) cnt from score;
2、求分数的最大值(max)
select max(s_score) from score;
3、求分数的最小值(min)
select min(s_score) from score;
4、求分数的总和(sum)
select sum(s_score) from score;
5、求分数的平均值(avg)
select avg(s_score) from score;
1.4、limit语句
典型的查询会返回多行数据。limit子句用于限制返回的行数。
select * from score limit 5;
1.5、where语句
- 1、使用 where 子句,将不满足条件的行过滤掉
- 2、where 子句紧随from子句
- 3、案例实操
select * from score where s_score > 60;
1.6、算术运算符
运算符 | 描述 |
A+B | A和B 相加 |
A-B | A减去B |
A*B | A和B 相乘 |
A/B | A除以B |
A%B | A对B取余 |
A&B | A和B按位取与 |
A|B | A和B按位取或 |
A^B | A和B按位取异或 |
~A | A按位取反 |
1.7、比较运算
操作符 | 支持的数据类型 | 描述 |
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 B | STRING 类型 | B是一个SQL下的简单正则表达式,如果A与其匹配的话,则返回true;反之返回false。B的表达式说明如下:‘x%’表示A必须以字母‘x’开头,‘%x’表示A必须以字母’x’结尾,而‘%x%’表示A包含有字母’x’,可以位于开头,结尾或者字符串中间。如果使用NOT关键字则可达到相反的效果。like不是正则,而是通配符 |
A RLIKE B, A REGEXP B | STRING 类型 | B是一个正则表达式,如果A与其匹配,则返回true;反之返回false。匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。 |
1.8、逻辑运算符
操作符 | 操作 | 描述 |
A AND B | 逻辑并 | 如果A和B都是true则为true,否则false |
A OR B | 逻辑或 | 如果A或B或两者都是true则为true,否则false |
NOT A | 逻辑否 | 如果A为false则为true,否则false |
2、分组
2.1、group by语句
Group By 语句通常会和==聚合函数==一起使用,按照一个或者多个列队结果进行分组,然后对每个组执行聚合操作。
- 案例实操:
- (1)计算每个学生的平均分数
select s_id,avg(s_score) from score group by s_id;
- (2)计算每个学生最高的分数
select s_id,max(s_score) from score group by s_id;
2.2、having语句
having 与 where 不同点
- where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据
- where后面不能写分组函数,而having后面可以使用分组函数
- having只用于group by分组统计语句
案例实操
- 求每个学生的平均分数
select s_id,avg(s_score) from score group by s_id;
- 求每个学生平均分数大于60的人
select s_id,avg(s_score) as avgScore from score group by s_id having avgScore > 60;
3、join语句
3.1、等值join
- Hive支持通常的SQL JOIN语句,但是只支持等值连接,不支持非等值连接。
- 案例实操
- 根据学生和成绩表,查询学生姓名对应的成绩
3.2、表的别名
- 好处
- 使用别名可以简化查询。
- 使用表名前缀可以提高执行效率。
- 案例实操
- 合并老师与课程表
#hive当中创建course表并加载数据
create table course (c_id string,c_name string,t_id string)
row format delimited fields terminated by '\t';
load data local inpath '/kkb/install/hivedatas/course.csv' overwrite into table course;
select * from teacher t join course c on t.t_id = c.t_id;
3.3、内连接inner join
- 内连接:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
- join默认是inner join
- 案例实操
select * from teacher t inner join course c on t.t_id = c.t_id;
3.4、左外连接left outer join
- 左外连接:join操作符左边表中符合where子句的所有记录将会被返回。
- 案例实操
- 查询老师对应的课程
select * from teacher t left outer join course c on t.t_id = c.t_id;
3.5、右外连接right outer join
- 右外连接:join操作符右边表中符合where子句的所有记录将会被返回。
- 案例实操
select * from teacher t right outer join course c on t.t_id = c.t_id;
3.6、满外连接full outer join
- 满外连接:将会返回==所有表中==符合where语句条件的所有记录。如果任一表的指定字段没有符合条件的值的话,那么就使用null值替代。
- 案例实操
select * from teacher t full outer join course c on t.t_id = c.t_id;
3.7、多表连接
- 多个表使用join进行连接
- 注意:连接 n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
- 案例实操
- 多表连接查询,查询老师对应的课程,以及对应的分数,对应的学生
select * from teacher t left join course c on t.t_id = c.t_id
left join score s on c.c_id = s.c_id
left join stu on s.s_id = stu.id;
4、排序
4.1、order by 全局排序
- order by 说明
- 全局排序,只有一个reduce
- 使用 ORDER BY 子句排序
- asc ( ascend)
- 升序 (默认)
- desc (descend)
- 降序
- order by 子句在select语句的结尾
- 案例实操
- 查询学生的成绩,并按照分数降序排列
select * from score s order by s_score desc ;
4.2、按照别名排序
- 按照学生分数的平均值排序
select s_id,avg(s_score) avgscore from score group by s_id order by avgscore desc;
4.3、每个MapReduce内部排序(sort by)局部排序
- sort by:每个reducer内部进行排序,对全局结果集来说不是排序。
- 1、设置reduce个数
set mapreduce.job.reduces=3;
- 2、查看reduce的个数
set mapreduce.job.reduces;
- 3、查询成绩按照成绩降序排列
select * from score s sort by s.s_score;
- 4、将查询结果导入到文件中(按照成绩降序排列)
insert overwrite local directory '/kkb/install/hivedatas/sort'
select * from score s sort by s.s_score;
4.4、distribute by 分区排序
- distribute by:类似MR中partition,采集hash算法,在map端将查询的结果中hash值相同的结果分发到对应的reduce文件中。结合sort by使用。
- 注意
- Hive要求 distribute by 语句要写在 sort by 语句之前。
- 案例实操
- 先按照学生 sid 进行分区,再按照学生成绩进行排序
- 设置reduce的个数
set mapreduce.job.reduces=3;
- 通过distribute by 进行数据的分区,,将不同的sid 划分到对应的reduce当中去
insert overwrite local directory '/kkb/install/hivedatas/distribute'
select * from score distribute by s_id sort by s_score;
4.5、cluster by
- 当distribute by和sort by字段相同时,可以使用cluster by方式
- 除了distribute by 的功能外,还会对该字段进行排序,所以cluster by = distribute by + sort by
--以下两种写法等价
insert overwrite local directory '/kkb/install/hivedatas/distribute_sort' select * from score distribute by s_score sort by s_score;
insert overwrite local directory '/kkb/install/hivedatas/cluster' select * from score cluster by s_score;
八、hive客户端jdbc操作
1、启动hiveserver2的服务端
node03执行以下命令启动hiveserver2的服务端
cd /kkb/install/hive-1.1.0-cdh5.14.2/
nohup bin/hive --service hiveserver2 2>&1 &
九、hive的可视化工具dbeaver介绍以及使用
1、dbeaver的基本介绍
dbeaver是一个图形化的界面工具,专门用于与各种数据库的集成,通过dbeaver我们可以与各种数据库进行集成通过图形化界面的方式来操作我们的数据库与数据库表,类似于我们的sqlyog或者navicate
2、dbeaver的安装
https://github.com/dbeaver/dbeaver/releases
3、dbeaver的安装与使用
使用的版本是6.15这个版本,下载zip的压缩包,直接解压就可以使用,然后双击dbeaver.exe即可启动
- 第一步:双击dbeaver.exe然后启动dbeaver图形化界面
- 第二步:配置我们的主机名与端口号
九、Hive的参数传递
1、hive命令行
语法结构
hive [-hiveconf x=y]* [<-i filename>]* [<-f filename>|<-e query-string>] [-S]
说明:
1、 -i 从文件初始化HQL。
2、 -e从命令行执行指定的HQL
3、 -f 执行HQL脚本
4、 -v 输出执行的HQL语句到控制台
5、 -p <port> connect to Hive Server on port number
6、 -hiveconf x=y Use this to set hive/hadoop configuration variables. 设置hive运行时候的参数配置
2、hive参数配置方式
Hive参数大全:
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
开发Hive应用时,不可避免地需要设定Hive的参数。设定Hive的参数可以调优HQL代码的执行效率,或帮助定位问题。然而实践中经常遇到的一个问题是,为什么设定的参数没有起作用?这通常是错误的设定方式导致的。
对于一般参数,有以下三种设定方式:
配置文件 hive-site.xml
命令行参数 启动hive客户端的时候可以设置参数
参数声明 进入客户端以后设置的一些参数 set
配置文件:Hive的配置文件包括
用户自定义配置文件:$HIVE_CONF_DIR/hive-site.xml
默认配置文件:$HIVE_CONF_DIR/hive-default.xml
用户自定义配置会覆盖默认配置。
另外,Hive也会读入Hadoop的配置,因为Hive是作为Hadoop的客户端启动的,Hive的配置会覆盖Hadoop的配置。配置文件的设定对本机启动的所有Hive进程都有效。
命令行参数:启动Hive(客户端或Server方式)时,可以在命令行添加-hiveconf param=value来设定参数,例如:
bin/hive -hiveconf hive.root.logger=INFO,console
这一设定对本次启动的Session(对于Server方式启动,则是所有请求的Sessions)有效。
参数声明:可以在HQL中使用SET关键字设定参数,例如:
set mapred.reduce.tasks=100;
这一设定的作用域也是session级的。
上述三种设定方式的优先级依次递增。即参数声明覆盖命令行参数,命令行参数覆盖配置文件设定。注意某些系统级的参数,例如log4j相关的设定,必须用前两种方式设定,因为那些参数的读取在Session建立以前已经完成了。
参数声明 > 命令行参数 > 配置文件参数(hive)
3、使用变量传递参数
实际工作当中,我们一般都是将hive的hql语法开发完成之后,就写入到一个脚本里面去,然后定时的通过命令 hive -f 去执行hive的语法即可,然后通过定义变量来传递参数到hive的脚本当中去,那么我们接下来就来看看如何使用hive来传递参数。
hive0.9以及之前的版本是不支持传参的 hive1.0版本之后支持 hive -f 传递参数
在hive当中我们一般可以使用hivevar或者hiveconf来进行参数的传递
hiveconf使用说明
hiveconf用于定义HIVE执行上下文的属性(配置参数),可覆盖覆盖hive-site.xml(hive-default.xml)中的参数值,如用户执行目录、日志打印级别、执行队列等。例如我们可以使用hiveconf来覆盖我们的hive属性配置,
hiveconf变量取值必须要使用hiveconf作为前缀参数,具体格式如下:
${hiveconf:key}
bin/hive --hiveconf "mapred.job.queue.name=root.default"
hivevar使用说明
hivevar用于定义HIVE运行时的变量替换,类似于JAVA中的“PreparedStatement”,与${key}配合使用或者与 ${hivevar:key}
对于hivevar取值可以不使用前缀hivevar,具体格式如下:
使用前缀:
${hivevar:key}
不使用前缀:
${key}
--hivevar name=zhangsan ${hivevar:name}
也可以这样取值 ${name}
define使用说明
define与hivevar用途完全一样,还有一种简写“-d
bin/hive --hiveconf "mapred.job.queue.name=root.default" -d my="201809" --database mydb
执行SQL
select * from mydb where concat(year, month) = ${my} limit 10;
hiveconf与hivevar使用实战
需求:hive当中执行以下hql语句,并将参数全部都传递进去
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;
- 第一步:创建student表并加载数据
hive (myhive)> create external table student
(s_id string,s_name string,s_birth string , s_sex string )
row format delimited fields terminated by '\t';
hive (myhive)> load data local inpath '/kkb/install/hivedatas/student.csv' overwrite into table student;
- 第二步:定义hive脚本
开发hql脚本,并使用hiveconf和hivevar进行参数穿肚
node03执行以下命令定义hql脚本
cd /kkb/instal/hivedatas
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脚本并传递参数
node03执行以下命令并
[root@node03 hive-1.1.0-cdh5.14.2]# bin/hive --hiveconf month=201807 --hivevar s_score=80 --hivevar c_id=03 -f /kkb/install/hivedatas/hivevariable.hql
十、Hive的常用函数
系统内置函数
1.查看系统自带的函数
hive> show functions;
2.显示自带的函数的用法
hive> desc function upper;
3.详细显示自带的函数的用法
hive> desc function extended upper;
1、数值计算
1.1、取整函数:round
语法: round(double a)
返回值: BIGINT
说明: 返回double类型的整数值部分 (遵循四舍五入)
hive> select round(3.1415926) from tableName;
3
hive> select round(3.5) from tableName;
4
hive> create table tableName as select round(9542.158) from tableName;
1.2、指定精度取整函数:round
语法: round(double a, int d)
返回值: DOUBLE
说明: 返回指定精度d的double类型
hive> select round(3.1415926,4) from tableName;
3.1416
1.3、向下取整函数:floor
语法: floor(double a)
返回值: BIGINT
说明: 返回等于或者小于该double变量的最大的整数
hive> select floor(3.1415926) from tableName;
3
hive> select floor(25) from tableName;
25
1.4、向上取整函数:ceil
语法: ceil(double a)
返回值: BIGINT
说明: 返回等于或者大于该double变量的最小的整数
hive> select ceil(3.1415926) from tableName;
4
hive> select ceil(46) from tableName;
46
1.5、向上取整函数:ceiling
语法: ceiling(double a)
返回值: BIGINT
说明: 与ceil功能相同
hive> select ceiling(3.1415926) from tableName;
4
hive> select ceiling(46) from tableName;
46
1.6、取随机数函数:rand
语法: rand(),rand(int seed)
返回值: double
说明: 返回一个0到1范围内的随机数。如果指定种子seed,则会等到一个稳定的随机数序列
hive> select rand() from tableName;
0.5577432776034763
hive> select rand() from tableName;
0.6638336467363424
hive> select rand(100) from tableName;
0.7220096548596434
hive> select rand(100) from tableName;
0.7220096548596434
2、日期函数
2.1、unix时间戳转日期函数:from_unixtime
语法: from_unixtime(bigint unixtime[, string format])
返回值: string
说明: 转化UNIX时间戳(从1970-01-01 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式
hive> select from_unixtime(1323308943,'yyyyMMdd') from tableName;
20111208
2.2、获取当前unix时间戳函数:unix_timestamp
语法: unix_timestamp()
返回值: bigint
说明: 获得当前时区的UNIX时间戳
hive> select unix_timestamp() from tableName;
1323309615
2.3、日期转unix时间戳函数:unix_timestamp
语法: unix_timestamp(string date)
返回值: bigint
说明: 转换格式为"yyyy-MM-dd HH:mm:ss"的日期到UNIX时间戳。如果转化失败,则返回0。
hive> select unix_timestamp('2011-12-07 13:01:03') from tableName;
1323234063
2.4、指定格式日期转unix时间戳函数:unix_timestamp
语法: unix_timestamp(string date, string pattern)
返回值: bigint
说明: 转换pattern格式的日期到UNIX时间戳。如果转化失败,则返回0。
hive> select unix_timestamp('20111207 13:01:03','yyyyMMdd HH:mm:ss') from tableName;
1323234063
2.5、日期时间转日期函数:to_date
语法: to_date(string timestamp)
返回值: string
说明: 返回日期时间字段中的日期部分。
hive> select to_date('2011-12-08 10:03:01') from tableName;
2011-12-08
2.6、日期转年函数:year
语法: year(string date)
返回值: int
说明: 返回日期中的年。
hive> select year('2011-12-08 10:03:01') from tableName;
2011
hive> select year('2012-12-08') from tableName;
2012
2.7、日期转月函数:month
语法: month (string date)
返回值: int
说明: 返回日期中的月份。
hive> select month('2011-12-08 10:03:01') from tableName;
12
hive> select month('2011-08-08') from tableName;
8
2.8、日期转天函数:day
语法: day (string date)
返回值: int
说明: 返回日期中的天。
hive> select day('2011-12-08 10:03:01') from tableName;
8
hive> select day('2011-12-24') from tableName;
24
2.9、日期转小时函数:hour
语法: hour (string date)
返回值: int
说明: 返回日期中的小时。
hive> select hour('2011-12-08 10:03:01') from tableName;
10
2.10、日期转分钟函数:minute
语法: minute (string date)
返回值: int
说明: 返回日期中的分钟。
hive> select minute('2011-12-08 10:03:01') from tableName;
3
hive> select second('2011-12-08 10:03:01') from tableName;
1
2.11、日期转周函数:weekofyear
语法: weekofyear (string date)
返回值: int
说明: 返回日期在当前的周数。
2.12、日期比较函数:datediff
语法: datediff(string enddate, string startdate)
返回值: int
说明: 返回结束日期减去开始日期的天数。
hive> select datediff('2012-12-08','2012-05-09') from tableName;
213
2.13、日期增加函数:date_add
语法: date_add(string startdate, int days)
返回值: string
说明: 返回开始日期startdate增加days天后的日期。
hive> select date_add('2012-12-08',10) from tableName;
2012-12-18
2.14、日期减少函数:date_sub
语法: date_sub (string startdate, int days)
返回值: string
说明: 返回开始日期startdate减少days天后的日期。
hive> select date_sub('2012-12-08',10) from tableName;
2012-11-28
3、条件函数
3.1、if函数:if
语法: if(boolean testCondition, T valueTrue, T valueFalseOrNull)
返回值: T
说明: 当条件testCondition为TRUE时,返回valueTrue;否则返回valueFalseOrNull
hive> select if(1=2,100,200) from tableName;
200
hive> select if(1=1,100,200) from tableName;
100
3.2、非空查找函数:coalesce
语法: COALESCE(T v1, T v2, …)
返回值: T
说明: 返回参数中的第一个非空值;如果所有值都为NULL,那么返回NULL
hive> select COALESCE(null,'100','50') from tableName;
100
3.3、条件判断函数:case
语法: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
返回值: T
说明:如果a等于b,那么返回c;如果a等于d,那么返回e;否则返回f
hive> Select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end from tableName;
mary
hive> Select case 200 when 50 then 'tom' when 100 then 'mary' else 'tim' end from tableName;
tim
3.4、条件判断函数:case
语法: CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END
返回值: T
说明:如果a为TRUE,则返回b;如果c为TRUE,则返回d;否则返回e
hive> select case when 1=2 then 'tom' when 2=2 then 'mary' else 'tim' end from tableName;
mary
hive> select case when 1=1 then 'tom' when 2=2 then 'mary' else 'tim' end from tableName;
tom
case...when...例子
#创建表
create table employee(
empid int,
deptid int,
sex string,
salary double
)row format delimited
fields terminated by ' ';
# employee.txt 数据文件
1 10 female 5500.0
2 10 male 4500.0
3 20 female 1900.0
4 20 male 4800.0
5 30 female 6500.0
6 30 female 14500.0
7 30 male 44500.0
8 40 male 6500.0
9 40 male 7500.0
#表结构
# desc employee;
empid int
deptid int
sex string
salary double
#表记录
select * from employee;
1 10 female 5500.0
2 10 male 4500.0
3 20 female 1900.0
4 20 male 4800.0
5 40 female 6500.0
6 40 female 14500.0
7 40 male 44500.0
8 50 male 6500.0
9 50 male 7500.0
################### 将员工按照薪资待遇划分等级 薪水小于五千的,打上低等收入的标签,收入在5000到10000打上中等收入标签,收入大于10000打上高等收入标签 ###################
################### 将员工按照性别打上标识 ###################
select *,
case
when salary < 5000 then "低等收入"
when salary>= 5000 and salary < 10000 then "中等收入"
when salary > 10000 then "高等收入"
end as level,
case sex
when "female" then 1
when "male" then 0
end as flag
from employee;
#统计结果
1 10 female 5500.0 中等收入 1
2 10 male 4500.0 低等收入 0
3 20 female 1900.0 低等收入 1
4 20 male 4800.0 低等收入 0
5 40 female 6500.0 中等收入 1
6 40 female 14500.0 高等收入 1
7 40 male 44500.0 高等收入 0
8 50 male 6500.0 中等收入 0
9 50 male 7500.0 中等收入 0
4、字符串函数
4.1、字符串长度函数:length
语法: length(string A)
返回值: int
说明:返回字符串A的长度
hive> select length('abcedfg') from tableName;
4.2、字符串反转函数:reverse
语法: reverse(string A)
返回值: string
说明:返回字符串A的反转结果
hive> select reverse('abcedfg') from tableName;
gfdecba
4.3、字符串连接函数:concat
语法: concat(string A, string B…)
返回值: string
说明:返回输入字符串连接后的结果,支持任意个输入字符串
hive> select concat('abc','def','gh') from tableName;
abcdefgh
4.4、字符串连接并指定字符串分隔符:concat_ws
语法: concat_ws(string SEP, string A, string B…)
返回值: string
说明:返回输入字符串连接后的结果,SEP表示各个字符串间的分隔符
hive> select concat_ws(',','abc','def','gh')from tableName;
abc,def,gh
4.5、字符串截取函数:substr
语法: substr(string A, int start),substring(string A, int start)
返回值: string
说明:返回字符串A从start位置到结尾的字符串
hive> select substr('abcde',3) from tableName;
cde
hive> select substring('abcde',3) from tableName;
cde
hive> select substr('abcde',-1) from tableName; (和ORACLE相同)
e
4.6、字符串截取函数:substr、substring
语法: substr(string A, int start, int len),substring(string A, int start, int len)
返回值: string
说明:返回字符串A从start位置开始,长度为len的字符串
hive> select substr('abcde',3,2) from tableName;
cd
hive> select substring('abcde',3,2) from tableName;
cd
hive>select substring('abcde',-2,2) from tableName;
de
4.7、字符串转大写函数:upper、ucase
语法: upper(string A) ucase(string A)
返回值: string
说明:返回字符串A的大写格式
hive> select upper('abSEd') from tableName;
ABSED
hive> select ucase('abSEd') from tableName;
ABSED
4.8、字符串转小写函数:lower、lcase
语法: lower(string A) lcase(string A)
返回值: string
说明:返回字符串A的小写格式
hive> select lower('abSEd') from tableName;
absed
hive> select lcase('abSEd') from tableName;
absed
4.9、去空格函数:trim
语法: trim(string A)
返回值: string
说明:去除字符串两边的空格
hive> select trim(' abc ') from tableName;
abc
4.10、url解析函数:parse_url
语法:parse_url(string urlString, string partToExtract [, string keyToExtract])
返回值: string
说明:返回URL中指定的部分。partToExtract的有效值为:HOST, PATH,QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO.
hive> select parse_url
('https://www.tableName.com/path1/p.php?k1=v1&k2=v2#Ref1', 'HOST')
from tableName;
www.tableName.com
hive> select parse_url
('https://www.tableName.com/path1/p.php?k1=v1&k2=v2#Ref1', 'QUERY', 'k1')
from tableName;
v1
4.11、json解析函数:get_json_object
语法: get_json_object(string json_string, string path)
返回值: string
说明:解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NULL。
hive> select get_json_object('{"store":{"fruit":\[{"weight":8,"type":"apple"},{"weight":9,"type":"pear"}], "bicycle":{"price":19.95,"color":"red"} },"email":"amy@only_for_json_udf_test.net","owner":"amy"}','$.owner') from tableName;
4.12、重复字符串函数:repeat
语法: repeat(string str, int n)
返回值: string
说明:返回重复n次后的str字符串
hive> select repeat('abc',5) from tableName;
abcabcabcabcabc
4.13、分割字符串函数:split
语法: split(string str, string pat)
返回值: array
说明: 按照pat字符串分割str,会返回分割后的字符串数组
hive> select split('abtcdtef','t') from tableName;
["ab","cd","ef"]
5、集合函数统计
5.1、个数统计函数:count
语法: count(*), count(expr), count(DISTINCT expr[, expr_.])
返回值:Int
说明: count(*)统计检索出的行的个数,包括NULL值的行;count(expr)返回指定字段的非空值的个数;count(DISTINCTexpr[, expr_.])返回指定字段的不同的非空值的个数
hive> select count(*) from tableName;
20
hive> select count(distinct t) from tableName;
10
5.2、总和统计函数:sum
语法: sum(col), sum(DISTINCT col)
返回值: double
说明: sum(col)统计结果集中col的相加的结果;sum(DISTINCT col)统计结果中col不同值相加的结果
hive> select sum(t) from tableName;
100
hive> select sum(distinct t) from tableName;
70
5.3、平均值统计函数:avg
语法: avg(col), avg(DISTINCT col)
返回值: double
说明: avg(col)统计结果集中col的平均值;avg(DISTINCT col)统计结果中col不同值相加的平均值
hive> select avg(t) from tableName;
50
hive> select avg (distinct t) from tableName;
30
5.4、最小值统计函数:mix
语法: min(col)
返回值: double
说明: 统计结果集中col字段的最小值
hive> select min(t) from tableName;
20
5.5、最大值统计函数:max
语法: maxcol)
返回值: double
说明: 统计结果集中col字段的最大值
hive> select max(t) from tableName;
120
6、复合类型构建函数
6.1、map类型构建:map
语法: map (key1, value1, key2, value2, …)
说明:根据输入的key和value对构建map类型
create table score_map(name string, score map<string,int>)
row format delimited fields terminated by '\t'
collection items terminated by ',' map keys terminated by ':';
创建数据内容如下并加载数据
cd /kkb/install/hivedatas/
vim score_map.txt
zhangsan 数学:80,语文:89,英语:95
lisi 语文:60,数学:80,英语:99
加载数据到hive表当中去
load data local inpath '/kkb/install/hivedatas/score_map.txt' overwrite into table score_map;
map结构数据访问:
获取所有的value:
select name,map_values(score) from score_map;
获取所有的key:
select name,map_keys(score) from score_map;
按照key来进行获取value值
select name,score["数学"] from score_map;
查看map元素个数
select name,size(score) from score_map;
6.2、struct类型构建:struck
语法: struct(val1, val2, val3, …)
说明:根据输入的参数构建结构体struct类型,似于C语言中的结构体,内部数据通过X.X来获取,假设我们的数据格式是这样的,电影ABC,有1254人评价过,打分为7.4分
创建struct表
hive> create table movie_score( name string, info struct<number:int,score:float> )row format delimited fields terminated by "\t" collection items terminated by ":";
加载数据
cd /kkb/install/hivedatas/
vim struct.txt
ABC 1254:7.4
DEF 256:4.9
XYZ 456:5.4
加载数据
load data local inpath '/kkb/install/hivedatas/struct.txt' overwrite into table movie_score;
hive当中查询数据
hive> select * from movie_score;
hive> select info.number,info.score from movie_score;
OK
1254 7.4
256 4.9
456 5.4
6.3、array类型构建:array
语法: array(val1, val2, …)
说明:根据输入的参数构建数组array类型
hive> create table person(name string,work_locations array<string>)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
COLLECTION ITEMS TERMINATED BY ',';
加载数据到person表当中去
cd /kkb/install/hivedatas/
vim person.txt
数据内容格式如下
biansutao beijing,shanghai,tianjin,hangzhou
linan changchu,chengdu,wuhan
加载数据
hive > load data local inpath '/kkb/install/hivedatas/person.txt' overwrite into table person;
查询所有数据数据
hive > select * from person;
按照下表索引进行查询
hive > select work_locations[0] from person;
查询所有集合数据
hive > select work_locations from person;
查询元素个数
hive > select size(work_locations) from person;
7、复杂类型长度统计函数
7.1、map类型长度函数:size(map)
语法: size(Map<k .V>)
返回值: int
说明: 返回map类型的长度
hive> select size(t) from map_table2;
2
7.2、array类型长度函数:size(arry)
语法: size(Array<T>)
返回值: int
说明: 返回array类型的长度
hive> select size(t) from arr_table2;
4
7.3、类型转换函数
类型转换函数: cast
语法: cast(expr as <type>)
返回值: Expected "=" to follow "type"
说明: 返回转换后的数据类型
hive> select cast('1' as bigint) from tableName;
1
8、hive当中的lateral view 与 explode以及reflect和分析函数
8.1、使用explode函数将hive表中的Map和Array字段数据进行拆分
lateral view用于和split、explode等UDTF一起使用的,能将一行数据拆分成多行数据,在此基础上可以对拆分的数据进行聚合,lateral view首先为原始表的每行调用UDTF,UDTF会把一行拆分成一行或者多行,lateral view在把结果组合,产生一个支持别名表的虚拟表。其中explode还可以用于将hive一列中复杂的array或者map结构拆分成多行
需求:现在有数据格式如下
zhangsan child1,child2,child3,child4 k1:v1,k2:v2
lisi child5,child6,child7,child8 k3:v3,k4:v4
字段之间使用\t分割,需求将所有的child进行拆开成为一列
+----------+--+
| mychild |
+----------+--+
| child1 |
| child2 |
| child3 |
| child4 |
| child5 |
| child6 |
| child7 |
| child8 |
+----------+--+
将map的key和value也进行拆开,成为如下结果
+-----------+-------------+--+
| mymapkey | mymapvalue |
+-----------+-------------+--+
| k1 | v1 |
| k2 | v2 |
| k3 | v3 |
| k4 | v4 |
+-----------+-------------+--+
- 第一步:创建hive数据库
创建hive数据库
hive (default)> create database hive_explode;
hive (default)> use hive_explode;
- 第二步:创建hive表,然后使用explode拆分map和array
hive (hive_explode)> create table hive_explode.t3(name string,children array<string>,address Map<string,string>) row format delimited fields terminated by '\t' collection items terminated by ',' map keys terminated by ':' stored as textFile;
- 第三步:加载数据
node03执行以下命令创建表数据文件
cd /kkb/install/hivedatas/
vim maparray
数据内容格式如下
zhangsan child1,child2,child3,child4 k1:v1,k2:v2
lisi child5,child6,child7,child8 k3:v3,k4:v4
hive表当中加载数据
hive (hive_explode)> load data local inpath '/kkb/install/hivedatas/maparray' into table hive_explode.t3;
- 第四步:使用explode将hive当中数据拆开
将array当中的数据拆分开
hive (hive_explode)> SELECT explode(children) AS myChild FROM hive_explode.t3;
将map当中的数据拆分开
hive (hive_explode)> SELECT explode(address) AS (myMapKey, myMapValue) FROM hive_explode.t3;
8.2、使用explode拆分json字符串
需求:现在有一些数据格式如下:
a:shandong,b:beijing,c:hebei|1,2,3,4,5,6,7,8,9|[{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}]
其中字段与字段之间的分隔符是 |
我们要解析得到所有的monthSales对应的值为以下这一列(行转列)
4900
2090
6987
- 第一步:创建hive表
hive (hive_explode)> create table hive_explode.explode_lateral_view (area string, goods_id string, sale_info string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '|' STORED AS textfile;
- 第二步:准备数据并加载数据
准备数据如下
cd /kkb/install/hivedatas
vim explode_json
a:shandong,b:beijing,c:hebei|1,2,3,4,5,6,7,8,9|[{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}]
加载数据到hive表当中去
hive (hive_explode)> load data local inpath '/kkb/install/hivedatas/explode_json' overwrite into table hive_explode.explode_lateral_view;
- 第三步:使用explode拆分Array
hive (hive_explode)> select explode(split(goods_id,',')) as goods_id from hive_explode.explode_lateral_view;
- 第四步:使用explode拆解Map
hive (hive_explode)> select explode(split(area,',')) as area from hive_explode.explode_lateral_view;
- 第五步:拆解json字段
hive (hive_explode)> select explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{')) as sale_info from hive_explode.explode_lateral_view;
然后我们想用get_json_object来获取key为monthSales的数据:
hive (hive_explode)> select get_json_object(explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{')),'$.monthSales') as sale_info from hive_explode.explode_lateral_view;
然后出现异常FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions
UDTF explode不能写在别的函数内
如果你这么写,想查两个字段,select explode(split(area,',')) as area,good_id from explode_lateral_view;
会报错FAILED: SemanticException 1:40 Only a single expression in the SELECT clause is supported with UDTF's. Error encountered near token 'good_id'
使用UDTF的时候,只支持一个字段,这时候就需要LATERAL VIEW出场了
8.3、配合LATERAL VIEW使用
配合lateral view查询多个字段
hive (hive_explode)> select goods_id2,sale_info from explode_lateral_view LATERAL VIEW explode(split(goods_id,','))goods as goods_id2;
其中LATERAL VIEW explode(split(goods_id,','))goods相当于一个虚拟表,与原表explode_lateral_view笛卡尔积关联。
也可以多重使用
hive (hive_explode)> select goods_id2,sale_info,area2 from explode_lateral_view LATERAL VIEW explode(split(goods_id,','))goods as goods_id2 LATERAL VIEW explode(split(area,','))area as area2;
也是三个表笛卡尔积的结果
最终,我们可以通过下面的句子,把这个json格式的一行数据,完全转换成二维表的方式展现
hive (hive_explode)> select get_json_object(concat('{',sale_info_1,'}'),'$.source') as source, get_json_object(concat('{',sale_info_1,'}'),'$.monthSales') as monthSales, get_json_object(concat('{',sale_info_1,'}'),'$.userCount') as monthSales, get_json_object(concat('{',sale_info_1,'}'),'$.score') as monthSales from explode_lateral_view LATERAL VIEW explode(split(regexp_replace(regexp_replace(sale_info,'\\[\\{',''),'}]',''),'},\\{'))sale_info as sale_info_1;
总结:
Lateral View通常和UDTF一起出现,为了解决UDTF不允许在select字段的问题。
Multiple Lateral View可以实现类似笛卡尔乘积。
Outer关键字可以把不输出的UDTF的空结果,输出成NULL,防止丢失数据。
9、列转行
9.1、相关函数介绍
CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意个输入字符串;
CONCAT_WS(separator, str1, str2,...):它是一个特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将为 NULL。这个函数会跳过分隔符参数后的任何 NULL 和空字符串。分隔符将被加到被连接的字符串之间;
COLLECT_SET(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段。
9.2、数据准备
name | constellation | blood_type |
孙悟空 | 白羊座 | A |
老王 | 射手座 | A |
宋宋 | 白羊座 | B |
猪八戒 | 白羊座 | A |
冰冰 | 射手座 | A |
9.3、需求
把星座和血型一样的人归类到一起。结果如下:
射手座,A 老王|冰冰
白羊座,A 孙悟空|猪八戒
白羊座,B 宋宋
9.4、创建本地constellation.txt,导入数据
node03服务器执行以下命令创建文件,注意数据使用\t进行分割
cd /kkb/install/hivedatas
vim constellation.txt
孙悟空 白羊座 A
老王 射手座 A
宋宋 白羊座 B
猪八戒 白羊座 A
凤姐 射手座 A
9.5、创建hive表并导入数据
hive (hive_explode)> create table person_info( name string, constellation string, blood_type string) row format delimited fields terminated by "\t";
hive (hive_explode)> load data local inpath '/kkb/install/hivedatas/constellation.txt' into table person_info;
9.6、按需求查询数据
hive (hive_explode)> select t1.base, concat_ws('|', collect_set(t1.name)) name from (select name, concat(constellation, "," , blood_type) base from person_info) t1 group by t1.base;
10、行转列
10.1、函数说明
EXPLODE(col):将hive一列中复杂的array或者map结构拆分成多行。
LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解释:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。
10.2、数据准备
数据内容如下,字段之间都是使用\t进行分割
cd /kkb/install/hivedatas
vim movie.txt
《疑犯追踪》 悬疑,动作,科幻,剧情
《Lie to me》 悬疑,警匪,动作,心理,剧情
《战狼2》 战争,动作,灾难
10.3、需求
将电影分类中的数组数据展开。结果如下:
《疑犯追踪》 悬疑
《疑犯追踪》 动作
《疑犯追踪》 科幻
《疑犯追踪》 剧情
《Lie to me》 悬疑
《Lie to me》 警匪
《Lie to me》 动作
《Lie to me》 心理
《Lie to me》 剧情
《战狼2》 战争
《战狼2》 动作
《战狼2》 灾难
10.4、创建hive表并导入数据
hive (hive_explode)> create table movie_info(movie string, category array<string>) row format delimited fields terminated by "\t" collection items terminated by ",";
load data local inpath "/kkb/install/hivedatas/movie.txt" into table movie_info;
10.5、按需求查询数据
hive (hive_explode)> select movie, category_name from movie_info lateral view explode(category) table_tmp as category_name;
11、reflect函数
reflect函数可以支持在sql中调用java中的自带函数,秒杀一切udf函数。
使用java.lang.Math当中的Max求两列中最大值
创建hive表
hive (hive_explode)> create table test_udf(col1 int,col2 int) row format delimited fields terminated by ',';
准备数据并加载数据
cd /kkb/install/hivedatas
vim test_udf
1,2
4,3
6,4
7,5
5,6
加载数据
hive (hive_explode)> load data local inpath '/kkb/install/hivedatas/test_udf' overwrite into table test_udf;
使用java.lang.Math当中的Max求两列当中的最大值
hive (hive_explode)> select reflect("java.lang.Math","max",col1,col2) from test_udf;
不同记录执行不同的java内置函数
创建hive表
hive (hive_explode)> create table test_udf2(class_name string,method_name string,col1 int , col2 int) row format delimited fields terminated by ',';
准备数据
cd /export/servers/hivedatas
vim test_udf2
java.lang.Math,min,1,2
java.lang.Math,max,2,3
加载数据
hive (hive_explode)> load data local inpath '/kkb/install/hivedatas/test_udf2' overwrite into table test_udf2;
执行查询
hive (hive_explode)> select reflect(class_name,method_name,col1,col2) from test_udf2;
判断是否为数字
使用apache commons中的函数,commons下的jar已经包含在hadoop的classpath中,所以可以直接使用。
使用方式如下:
hive (hive_explode)> select reflect("org.apache.commons.lang.math.NumberUtils","isNumber","123");
十七、hive表的数据压缩
17.1、数据的压缩说明
- 压缩模式评价
- 可使用以下三种标准对压缩方式进行评价
- 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 |
http://google.github.io/snappy/
On a single core of a Core i7 processor in 64-bit mode, Snappy compresses at about 250 MB/sec or more and decompresses at about 500 MB/sec or more.
17.2、压缩配置参数
要在Hadoop中启用压缩,可以配置如下参数(mapred-site.xml文件中):
参数 | 默认值 | 阶段 | 建议 |
io.compression.codecs (在core-site.xml中配置) | org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.BZip2Codec, org.apache.hadoop.io.compress.Lz4Codec | 输入压缩 | Hadoop使用文件扩展名判断是否支持某种编解码器 |
mapreduce.map.output.compress | false | mapper输出 | 这个参数设为true启用压缩 |
mapreduce.map.output.compress.codec | org.apache.hadoop.io.compress.DefaultCodec | mapper输出 | 使用LZO、LZ4或snappy编解码器在此阶段压缩数据 |
mapreduce.output.fileoutputformat.compress | false | reducer输出 | 这个参数设为true启用压缩 |
mapreduce.output.fileoutputformat.compress.codec | org.apache.hadoop.io.compress. DefaultCodec | reducer输出 | 使用标准工具或者编解码器,如gzip和bzip2 |
mapreduce.output.fileoutputformat.compress.type | RECORD | reducer输出 | SequenceFile输出使用的压缩类型:NONE和BLOCK |
17.3、开启map输出阶段压缩
开启map输出阶段压缩可以减少job中map和Reduce task间数据传输量。具体配置如下:
案例实操:
1)开启hive中间传输数据压缩功能
hive (default)>set hive.exec.compress.intermediate=true;
2)开启mapreduce中map输出压缩功能
hive (default)>set mapreduce.map.output.compress=true;
3)设置mapreduce中map输出数据的压缩方式
hive (default)>set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
4)执行查询语句
select count(1) from score;
17.4、开启reduce输出阶段压缩
当Hive将输出写入到表中时,输出内容同样可以进行压缩。属性hive.exec.compress.output控制着这个功能。用户可能需要保持默认设置文件中的默认值false,这样默认的输出就是非压缩的纯文本文件了。用户可以通过在查询语句或执行脚本中设置这个值为true,来开启输出结果压缩功能。
案例实操:
1)开启hive最终输出数据压缩功能
hive (default)>set hive.exec.compress.output=true;
2)开启mapreduce最终输出数据压缩
hive (default)>set mapreduce.output.fileoutputformat.compress=true;
3)设置mapreduce最终数据输出压缩方式
hive (default)> set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;
4)设置mapreduce最终数据输出压缩为块压缩
hive (default)>set mapreduce.output.fileoutputformat.compress.type=BLOCK;
5)测试一下输出结果是否是压缩文件
insert overwrite local directory '/kkb/install/hivedatas/snappy' select * from score distribute by s_id sort by s_id desc;
十一、hive表文件存储格式
Hive支持的存储数的格式主要有:TEXTFILE(行式存储) 、SEQUENCEFILE(行式存储)、ORC(列式存储)、PARQUET(列式存储)。
1、列式存储和行式存储
上图左边为逻辑表,右边第一个为行式存储,第二个为列式存储。
行存储的特点: 查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。select *
列存储的特点: 因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。 select 某些字段效率更高
TEXTFILE和SEQUENCEFILE的存储格式都是基于行存储的;
ORC和PARQUET是基于列式存储的。
2、TEXTFILE格式
默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
3、ORC格式
Orc (Optimized Row Columnar)是hive 0.11版里引入的新的存储格式。
可以看到每个Orc文件由1个或多个stripe组成,每个stripe250MB大小,这个Stripe实际相当于RowGroup概念,不过大小由4MB->250MB,这样能提升顺序读的吞吐率。每个Stripe里有三部分组成,分别是Index Data,Row Data,Stripe Footer:
一个orc文件可以分为若干个Stripe
一个stripe可以分为三个部分
indexData:某些列的索引数据
rowData :真正的数据存储
StripFooter:stripe的元数据信息
1)Index Data:一个轻量级的index,默认是每隔1W行做一个索引。这里做的索引只是记录某行的各字段在Row Data中的offset。
2)Row Data:存的是具体的数据,先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个Stream来存储。
3)Stripe Footer:存的是各个stripe的元数据信息
每个文件有一个File Footer,这里面存的是每个Stripe的行数,每个Column的数据类型信息等;每个文件的尾部是一个PostScript,这里面记录了整个文件的压缩类型以及FileFooter的长度信息等。在读取文件时,会seek到文件尾部读PostScript,从里面解析到File Footer长度,再读FileFooter,从里面解析到各个Stripe信息,再读各个Stripe,即从后往前读。
4、PARQUET格式
Parquet是面向分析型业务的列式存储格式,由Twitter和Cloudera合作开发,2015年5月从Apache的孵化器里毕业成为Apache顶级项目。
Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。
通常情况下,在存储Parquet数据的时候会按照Block大小设置行组的大小,由于一般情况下每一个Mapper任务处理数据的最小单位是一个Block,这样可以把每一个行组由一个Mapper任务处理,增大任务执行并行度。Parquet文件的格式如下图所示。
上图展示了一个Parquet文件的内容,一个文件中可以存储多个行组,文件的首位都是该文件的Magic Code,用于校验它是否是一个Parquet文件,Footer length记录了文件元数据的大小,通过该值和文件长度可以计算出元数据的偏移量,文件的元数据中包括每一个行组的元数据信息和该文件存储数据的Schema信息。除了文件中每一个行组的元数据,每一页的开始都会存储该页的元数据,在Parquet中,有三种类型的页:数据页、字典页和索引页。数据页用于存储当前行组中该列的值,字典页存储该列值的编码字典,每一个列块中最多包含一个字典页,索引页用来存储当前行组下该列的索引,目前Parquet中还不支持索引页。
5、主流文件存储格式对比试验
从存储文件的压缩比和查询速度两个角度对比。
存储文件的压缩比测试:
- 1)TEXTFILE
- (1)创建表,存储数据格式为TEXTFILE
use myhive;
create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE ;
- (2)向表中加载数据
load data local inpath '/kkb/install/hivedatas/log.data' into table log_text ;
- (3)查看表中数据大小,大小为18.1M
dfs -du -h /user/hive/warehouse/myhive.db/log_text;
18.1 M /user/hive/warehouse/log_text/log.data
- 2)ORC
- (1)创建表,存储数据格式为ORC
create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc ;
- (2)向表中加载数据
insert into table log_orc select * from log_text ;
- (3)查看表中数据大小
dfs -du -h /user/hive/warehouse/myhive.db/log_orc;
2.8 M /user/hive/warehouse/log_orc/123456_0
orc这种存储格式,默认使用了zlib压缩方式来对数据进行压缩,所以数据会变成了2.8M,非常小
- 3)PARQUET
- (1)创建表,存储数据格式为parquet
create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS PARQUET ;
- (2)向表中加载数据
insert into table log_parquet select * from log_text ;
- (3)查看表中数据大小
dfs -du -h /user/hive/warehouse/myhive.db/log_parquet;
13.1 M /user/hive/warehouse/log_parquet/123456_0
存储文件的压缩比总结:
ORC > Parquet > textFile
存储文件的查询速度测试:
1)TextFile
hive (default)> select count(*) from log_text;
_c0
100000
Time taken: 21.54 seconds, Fetched: 1 row(s)
2)ORC
hive (default)> select count(*) from log_orc;
_c0
100000
Time taken: 20.867 seconds, Fetched: 1 row(s)
3)Parquet
hive (default)> select count(*) from log_parquet;
_c0
100000
Time taken: 22.922 seconds, Fetched: 1 row(s)
存储文件的查询速度总结:
ORC > TextFile > Parquet
十二、存储和压缩的结合
ORC存储方式的压缩:
Key | Default | Notes |
orc.compress | ZLIB | high level compression (one of NONE, ZLIB, SNAPPY) |
orc.compress.size | 262,144 | number of bytes in each compression chunk |
orc.stripe.size | 67,108,864 | number of bytes in each stripe |
orc.row.index.stride | 10,000 | number of rows between index entries (must be >= 1000) |
orc.create.index | true | whether to create row indexes |
orc.bloom.filter.columns | "" | comma separated list of column names for which bloom filter should be created |
orc.bloom.filter.fpp | 0.05 | false positive probability for bloom filter (must >0.0 and <1.0) |
- 1)创建一个非压缩格式的ORC存储方式
- (1)建表语句
create table log_orc_none(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="NONE");
- (2)插入数据
insert into table log_orc_none select * from log_text ;
- (3)查看插入后数据
dfs -du -h /user/hive/warehouse/myhive.db/log_orc_none;
7.7 M /user/hive/warehouse/log_orc_none/123456_0
- 2)创建一个SNAPPY压缩的ORC存储方式
- (1)建表语句
create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="SNAPPY");
- (2)插入数据
insert into table log_orc_snappy select * from log_text ;
- (3)查看插入后数据
dfs -du -h /user/hive/warehouse/myhive.db/log_orc_snappy ;
3.8 M /user/hive/warehouse/log_orc_snappy/123456_0
- 3)上一节中默认创建的ORC存储方式,导入数据后的大小为
2.8 M /user/hive/warehouse/log_orc/123456_0
比Snappy压缩的还小。原因是orc存储文件默认采用ZLIB压缩。比snappy压缩的小。
- 4)存储方式和压缩总结:
在实际的项目开发当中,hive表的数据存储格式一般选择:orc或parquet。压缩方式一般选择snappy。
1、Fetch抓取
- Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算
- 例如:select * from score;
- 在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台
- 在hive-default.xml.template文件中 hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。
- 案例实操
- 把 hive.fetch.task.conversion设置成none,然后执行查询语句,都会执行mapreduce程序
set hive.fetch.task.conversion=none;
select * from score;
select s_id from score;
select s_id from score limit 3;
- 把hive.fetch.task.conversion设置成more,然后执行查询语句,如下查询方式都不会执行mapreduce程序。
set hive.fetch.task.conversion=more;
select * from score;
select s_id from score;
select s_id from score limit 3;
2、本地模式
- 在Hive客户端测试时,默认情况下是启用hadoop的job模式,把任务提交到集群中运行,这样会导致计算非常缓慢;
- Hive可以通过本地模式在单台机器上处理任务。对于小数据集,执行时间可以明显被缩短。
- 案例实操
--开启本地模式,并执行查询语句
set hive.exec.mode.local.auto=true; //开启本地mr
--设置local mr的最大输入数据量,当输入数据量小于这个值时采用local mr的方式,
--默认为134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
--设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,
--默认为4
set hive.exec.mode.local.auto.input.files.max=5;
--执行查询的sql语句
select * from student cluster by s_id;
--关闭本地运行模式
set hive.exec.mode.local.auto=false;
select * from student cluster by s_id;
3、表的优化
- 1 小表、大表 join
- 将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率;再进一步,可以使用map join让小的维度表(1000条以下的记录条数)先进内存。在map端完成reduce。
select count(distinct s_id) from score;
select count(s_id) from score group by s_id; 在map端进行聚合,效率更高
- 实际测试发现:新版的hive已经对小表 join 大表和大表 join 小表进行了优化。小表放在左边和右边已经没有明显区别。
- 多个表关联时,最好分拆成小段,避免大sql(无法控制中间Job)
- 2 大表 join 大表
- 1.空 key 过滤
- 有时join超时是因为某些key对应的数据太多,而相同key对应的数据都会发送到相同的reducer上,从而导致内存不够。
- 此时我们应该仔细分析这些异常的key,很多情况下,这些key对应的数据是异常数据,我们需要在SQL语句中进行过滤。
- 测试环境准备:
use myhive;
create table ori(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
create table nullidtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
load data local inpath '/kkb/install/hivedatas/hive_big_table/*' into table ori;
load data local inpath '/kkb/install/hivedatas/hive_have_null_id/*' into table nullidtable;
- 过滤空key与不过滤空key的结果比较
不过滤:
INSERT OVERWRITE TABLE jointable
SELECT a.* FROM nullidtable a JOIN ori b ON a.id = b.id;
结果:
No rows affected (152.135 seconds)
过滤:
INSERT OVERWRITE TABLE jointable
SELECT a.* FROM (SELECT * FROM nullidtable WHERE id IS NOT NULL ) a JOIN ori b ON a.id = b.id;
结果:
No rows affected (141.585 seconds)
- 2、空 key 转换
- 有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在 join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。
不随机分布:
set hive.exec.reducers.bytes.per.reducer=32123456;
set mapreduce.job.reduces=7;
INSERT OVERWRITE TABLE jointable
SELECT a.*
FROM nullidtable a
LEFT JOIN ori b ON CASE WHEN a.id IS NULL THEN 'hive' ELSE a.id END = b.id;
No rows affected (41.668 seconds)
- 结果:这样的后果就是所有为null值的id全部都变成了相同的字符串,及其容易造成数据的倾斜(所有的key相同,相同key的数据会到同一个reduce当中去)
为了解决这种情况,我们可以通过hive的rand函数,随机的给每一个为空的id赋上一个随机值,这样就不会造成数据倾斜
随机分布:
set hive.exec.reducers.bytes.per.reducer=32123456;
set mapreduce.job.reduces=7;
INSERT OVERWRITE TABLE jointable
SELECT a.*
FROM nullidtable a
LEFT JOIN ori b ON CASE WHEN a.id IS NULL THEN concat('hive', rand()) ELSE a.id END = b.id;
No rows affected (42.594 seconds)
- 3、大表join小表与小表join大表实测
- 需求:测试大表JOIN小表和小表JOIN大表的效率 (新的版本当中已经没有区别了,旧的版本当中需要使用小表)
- (1)建大表、小表和JOIN后表的语句
create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
create table smalltable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
create table jointable2(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
- (2)分别向大表和小表中导入数据
hive (default)> load data local inpath '/kkb/install/hivedatas/big_data' into table bigtable;
hive (default)>load data local inpath '/kkb/install/hivedatas/small_data' into table smalltable;
- (3)map join
- 如果不指定MapJoin 或者不符合 MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段完成join。容易发生数据倾斜。可以用 MapJoin 把小表全部加载到内存在map端进行join,避免reducer处理。
- 1、开启MapJoin参数设置
--默认为true
set hive.auto.convert.join = true;
- 2、大表小表的阈值设置(默认25M一下认为是小表)
set hive.mapjoin.smalltable.filesize=26214400;
- 3、MapJoin工作机制
首先是Task A,它是一个Local Task(在客户端本地执行的Task),负责扫描小表b的数据,将其转换成一个HashTable的数据结构,并写入本地的文件中,之后将该文件加载到DistributeCache中。
接下来是Task B,该任务是一个没有Reduce的MR,启动MapTasks扫描大表a,在Map阶段,根据a的每一条记录去和DistributeCache中b表对应的HashTable关联,并直接输出结果。
由于MapJoin没有Reduce,所以由Map直接输出结果文件,有多少个Map Task,就有多少个结果文件。
案例实操:
(1)开启Mapjoin功能
set hive.auto.convert.join = true; 默认为true
2)执行小表JOIN大表语句
INSERT OVERWRITE TABLE jointable2
SELECT b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
FROM smalltable s
JOIN bigtable b
ON s.id = b.id;
Time taken: 31.814 seconds
(3)执行大表JOIN小表语句
INSERT OVERWRITE TABLE jointable2
SELECT b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
FROM bigtable b
JOIN smalltable s
ON s.id = b.id;
Time taken: 28.46 seconds
- (4)group by
- 默认情况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就倾斜了。
- 并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。
- 开启Map端聚合参数设置
--是否在Map端进行聚合,默认为True
set hive.map.aggr = true;
--在Map端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
--有数据倾斜的时候进行负载均衡(默认是false)
set hive.groupby.skewindata = true;
当选项设定为 true,生成的查询计划会有两个MR Job。第一个MR Job中,Map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MR Job再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。
- (5)count(distinct)
- 数据量小的时候无所谓,数据量大的情况下,由于count distinct 操作需要用一个reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般count distinct使用先group by 再count的方式替换
- 环境准备:
create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
load data local inpath '/kkb/install/hivedatas/data/100万条大表数据(id除以10取整)/bigtable' into table bigtable;
--每个reduce任务处理的数据量 默认256000000(256M)
set hive.exec.reducers.bytes.per.reducer=32123456;
select count(distinct ip ) from log_text;
转换成
set hive.exec.reducers.bytes.per.reducer=32123456;
select count(ip) from (select ip from log_text group by ip) t;
虽然会多用一个Job来完成,但在数据量大的情况下,这个绝对是值得的。
- (6)笛卡尔积
- 尽量避免笛卡尔积,即避免join的时候不加on条件,或者无效的on条件
- Hive只能使用1个reducer来完成笛卡尔积。
4、使用分区剪裁、列剪裁
- 尽可能早地过滤掉尽可能多的数据量,避免大量数据流入外层SQL。
- 列剪裁
- 只获取需要的列的数据,减少数据输入。
- 分区裁剪
- 分区在hive实质上是目录,分区裁剪可以方便直接地过滤掉大部分数据。
- 尽量使用分区过滤,少用select *
环境准备:
create table ori(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';
load data local inpath '/home/admin/softwares/data/加递增id的原始数据/ori' into table ori;
load data local inpath '/home/admin/softwares/data/100万条大表数据(id除以10取整)/bigtable' into table bigtable;
先关联再Where:
SELECT a.id
FROM bigtable a
LEFT JOIN ori b ON a.id = b.id
WHERE b.id <= 10;
正确的写法是写在ON后面:先Where再关联
SELECT a.id
FROM ori a
LEFT JOIN bigtable b ON (a.id <= 10 AND a.id = b.id);
或者直接写成子查询:
SELECT a.id
FROM bigtable a
RIGHT JOIN (SELECT id
FROM ori
WHERE id <= 10
) b ON a.id = b.id;
5、并行执行
把一个sql语句中没有相互依赖的阶段并行去运行。提高集群资源利用率
--开启并行执行
set hive.exec.parallel=true;
--同一个sql允许最大并行度,默认为8。
set hive.exec.parallel.thread.number=16;
6、严格模式
- Hive提供了一个严格模式,可以防止用户执行那些可能意想不到的不好的影响的查询。
- 通过设置属性hive.mapred.mode值为默认是非严格模式**nonstrict** 。开启严格模式需要修改hive.mapred.mode值为**strict**,开启严格模式可以禁止3种类型的查询。
--设置非严格模式(默认)
set hive.mapred.mode=nonstrict;
--设置严格模式
set hive.mapred.mode=strict;
(1)对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行
--设置严格模式下 执行sql语句报错; 非严格模式下是可以的
select * from order_partition;
异常信息:Error: Error while compiling statement: FAILED: SemanticException [Error 10041]: No partition predicate found for Alias "order_partition" Table "order_partition"
(2)对于使用了order by语句的查询,要求必须使用limit语句
--设置严格模式下 执行sql语句报错; 非严格模式下是可以的
select * from order_partition where month='2019-03' order by order_price;
异常信息:Error: Error while compiling statement: FAILED: SemanticException 1:61 In strict mode, if ORDER BY is specified, LIMIT must also be specified. Error encountered near token 'order_price'
(3)限制笛卡尔积的查询
- 严格模式下,避免出现笛卡尔积的查询
7、JVM重用
JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。
Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间,具体多少需要根据具体业务场景测试得出。
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
</description>
</property>
我们也可以在hive当中通过
set mapred.job.reuse.jvm.num.tasks=10;
这个设置来设置我们的jvm重用
这个功能的缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。
8、推测执行
在分布式集群环境下,因为程序Bug(包括Hadoop本身的bug),负载不均衡或者资源分布不均等原因,会造成同一个作业的多个任务之间运行速度不一致,有些任务的运行速度可能明显慢于其他任务(比如一个作业的某个任务进度只有50%,而其他所有任务已经运行完毕),则这些任务会拖慢作业的整体执行进度。为了避免这种情况发生,Hadoop采用了推测执行(Speculative Execution)机制,它根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。
设置开启推测执行参数:Hadoop的mapred-site.xml文件中进行配置
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some map tasks
may be executed in parallel.</description>
</property>
<property>
<name>mapreduce.reduce.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some reduce tasks
may be executed in parallel.</description>
</property>
不过hive本身也提供了配置项来控制reduce-side的推测执行:
<property>
<name>hive.mapred.reduce.tasks.speculative.execution</name>
<value>true</value>
<description>Whether speculative execution for reducers should be turned on. </description>
</property>
关于调优这些推测执行变量,还很难给一个具体的建议。如果用户对于运行时的偏差非常敏感的话,那么可以将这些功能关闭掉。如果用户因为输入数据量很大而需要执行长时间的map或者Reduce task的话,那么启动推测执行造成的浪费是非常巨大大。(直接关闭)
9、压缩
Hive表中间数据压缩
#设置为true为激活中间数据压缩功能,默认是false,没有开启
set hive.exec.compress.intermediate=true;
#设置中间数据的压缩算法
set mapred.map.output.compression.codec= org.apache.hadoop.io.compress.SnappyCodec;
Hive表最终输出结果压缩
set hive.exec.compress.output=true;
set mapred.output.compression.codec=
org.apache.hadoop.io.compress.SnappyCodec;