hive第三课:Hive函数学习
Hive函数学习
SQL练习
1、count(*)、count(1) 、count('字段名') 区别
从执行结果来看
- count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL 最慢的
- count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL 最快的
- count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计 仅次于count(1)
从执行效率来看
- 如果列为主键,count(列名)效率优于count(1)
- 如果列不为主键,count(1)效率优于count(列名)
- 如果表中存在主键,count(主键列名)效率最优
- 如果表中只有一列,则count(*)效率最优
- 如果表有多列,且不存在主键,则count(1)效率优于count(*)
在工作中如果没有特殊的要求,就使用count(1)来进行计数。
hive语句的执行顺序
1.from2.join on 或 lateral view explode(需炸裂的列) tbl as 炸裂后的列名
3.where
4.group by
5.聚合函数 如Sum() avg() count(1)等
6.having 在此开始可以使用select中的别名
7.select 若包含over()开窗函数,此时select中的内容作为窗口函数的输入,窗口中所选的数据范围也是在group by,having之后,并不是针对where后的数据进行开窗,这点要注意。需要注意开窗函数的执行顺序及时间点。
8.distinct
9.order by
10.limit(建议:今后在大数据环境中,一张表的数据量肯定十分庞大的,养成加limit的习惯)
3、where 条件里不支持不等式子查询,实际上是支持 in、not in、exists、not exists( hive3.x版本是支持的 )
# 查询薪资大于SCOTT的薪资员工信息
-- 列出与“SCOTT”从事相同工作的所有员工。
select t1.EMPNO
,t1.ENAME
,t1.JOB
from emp t1
where t1.ENAME != "SCOTT" and t1.job in(
select job
from emp
where ENAME = "SCOTT");
7900,JAMES,CLERK,7698,1981-12-03,950,null,30
7902,FORD,ANALYST,7566,1981-12-03,3000,null,20
select t1.EMPNO
,t1.ENAME
,t1.JOB
from emp t1
where t1.ENAME != "SCOTT" and exists(
select job
from emp t2
where ENAME = "SCOTT"
and t1.job = t2.job
);
4、hive中大小写不敏感(列名无所谓大小写)
5、在hive中,数据中如果有null字符串,加载到表中的时候会变成 null (不是字符串)
如果需要判断 null,使用 某个字段名 is null 这样的方式来判断
或者使用 nvl() 函数,不能 直接 某个字段名 == null
6、使用explain查看SQL执行计划
面试题:hive中一条sql语句如何解析成MapReduce作业执行的?(hive的版本)
explain select t1.EMPNO
,t1.ENAME
,t1.JOB
from emp t1
where t1.ENAME != "SCOTT" and t1.job in(
select job
from emp
where ENAME = "SCOTT");
# 查看更加详细的执行计划,加上extended
explain extended select t1.EMPNO
,t1.ENAME
,t1.JOB
from emp t1
where t1.ENAME != "SCOTT" and t1.job in(
select job
from emp
where ENAME = "SCOTT");
Hive 常用函数
关系运算
// 等值比较 = == < = >
// 不等值比较 != <>
// 区间比较: select * from default.students where id between 1500100001 and 1500100010;
// 空值/非空值判断:isnull、isnotnull、nvl()、isnull()
// like、rlike、regexp用法
数值计算
取整函数(四舍五入):round
向上取整:ceil
向下取整:floor
条件函数(主要使用场景是数据清洗的过程中使用,有些构建表的过程也是需要的)
- if: if(表达式,如果表达式成立的返回值,如果表达式不成立的返回值) (重点)
- 条件表达式?表达式1:表达式2;
create table sc(
sno string,
cno string,
score bigint
)row format delimited fields terminated by '\n';
select sal,if(sal<2000,'低薪',if(sal>=2000 and sal<3000,'中等','高薪')) as level from emp;
select if(1>0,1,0);
select if(1>0,if(-1>0,-1,1),0);
select score,if(score>120,'优秀',if(score>100,'良好',if(score>90,'及格','不及格'))) as pingfen from sc;
- COALESCE
select COALESCE(null,'1','2'); // 1 从左往右 依次匹配 直到非空为止
select COALESCE('1',null,'2'); // 1
- case when(重点)
select sal,case when sal<2000 then '低薪'
when sal>=2000 and sal<3000 then '中等薪资'
else '高薪' end as level
from emp;
select score
,case when score>90 then '优秀'
when score>80 then '良好'
when score>=60 then '及格'
else '不及格'
end as pingfen
from sc;
select name
,case name when "施笑槐" then "槐ge"
when "吕金鹏" then "鹏ge"
when "单乐蕊" then "蕊jie"
else "算了不叫了"
end as nickname
from students limit 10;
注意条件的顺序
日期函数重点!!!
select from_unixtime(1717666208,'YYYY年MM月dd日 hh时mm分ss秒');
select from_unixtime(unix_timestamp(),'YYYY/MM/dd HH:mm:ss');
// '2021年01月14日' -> '2021-01-14'
select from_unixtime(unix_timestamp('2024年06月06日','yyyy年MM月dd日'),'yyyy-MM-dd');
// "04牛2021数加16强" -> "2021/04/16"
select from_unixtime(unix_timestamp("04牛2024数加11强","MM牛yyyy数加dd强"),"yyyy年MM月dd日");
字符串函数
concat('123','456'); // 123456
concat('123','456',null); // NULL
select concat_ws('#','a','b','c'); // a#b#c
select concat_ws('#','a','b','c',NULL); // a#b#c 可以指定分隔符,并且会自动忽略NULL
select concat_ws("|",cast(id as string),name,cast(age as string),gender,clazz) from students limit 10;
select substring("abcdefg",1); // abcdefg HQL中涉及到位置的时候 是从1开始计数
// '2021/01/14' -> '2021-01-14'
select concat_ws("-",substring('2021/01/14',1,4),substring('2021/01/14',6,2),substring('2021/01/14',9,2));
// 建议使用日期函数去做日期
select from_unixtime(unix_timestamp('2021/01/14','yyyy/MM/dd'),'yyyy-MM-dd');
select split("abcde,fgh",","); // ["abcde","fgh"]
select split("a,b,c,d,e,f",",")[2]; // c 数组的下标依旧是从0开始
select explode(split("abcde,fgh",",")); // abcde
// fgh
// 解析json格式的数据
select get_json_object('{"name":"zhangsan","age":18,"score":[{"course_name":"math","score":100},{"course_name":"english","score":60}]}',"$.score[0].score"); // 60
{
"name": "zhangsan",
"age": 18,
"score": [{
"course_name": "math",
"score": 100
}, {
"course_name": "english",
"score": 60
}]
}
$.score[0].score
Hive 中的wordCount
create table words(
words string
)row format delimited fields terminated by '\n';
// 数据
hello,java,hello,java,scala,python
hbase,hadoop,hadoop,hdfs,hive,hive
hbase,hadoop,hadoop,hdfs,hive,hive
select word,count(*) from (select explode(split(words,',')) word from words) a group by a.word;
// 结果
hadoop 4
hbase 2
hdfs 2
hello 2
hive 4
java 2
python 1
scala 1
1.1 Hive窗口函数
普通的聚合函数每组(Group by)只返回一个值,而开窗函数则可为窗口中的每行都返回一个值。
简单理解,就是对查询的结果多出一列,这一列可以是聚合值,也可以是排序值。
开窗函数一般就是说的是over()函数,其窗口是由一个 OVER 子句 定义的多行记录
开窗函数一般分为两类,聚合开窗函数和排序开窗函数。
-- 聚合格式
select sum(字段名) over([partition by 字段名] [ order by 字段名]) as 别名,
max(字段名) over() as 别名
from 表名;
-- 排序窗口格式
select rank() over([partition by 字段名] [ order by 字段名]) as 别名 from 表名;
注意点:
- over()函数中的分区、排序、指定窗口范围可组合使用也可以不指定,根据不同的业务需求结合使用
- over()函数中如果不指定分区,窗口大小是针对查询产生的所有数据,如果指定了分区,窗口大小是针对每个分区的数据
测试数据
-- 创建表
create table t_fraction(
name string,
subject string,
score int)
row format delimited fields terminated by ","
lines terminated by '\n';
-- 测试数据 fraction.txt
孙悟空,语文,10
孙悟空,数学,73
孙悟空,英语,15
猪八戒,语文,10
猪八戒,数学,73
猪八戒,英语,11
沙悟净,语文,22
沙悟净,数学,70
沙悟净,英语,31
唐玄奘,语文,21
唐玄奘,数学,81
唐玄奘,英语,23
-- 上传数据
load data local inpath '/usr/local/soft/bigdata17/xiaohu/data/fraction.txt' into table t_fraction;
1.1.1 聚合开窗函数
sum(求和)
min(最小)
max(最大)
avg(平均值)
count(计数)
lag(获取当前行上一行的数据)
--
select name,subject,score,sum(score) over() as sumover from t_fraction;
+-------+----------+--------+----------+
| name | subject | score | sumover |
+-------+----------+--------+----------+
| 唐玄奘 | 英语 | 23 | 321 |
| 唐玄奘 | 数学 | 81 | 321 |
| 唐玄奘 | 语文 | 21 | 321 |
| 沙悟净 | 英语 | 31 | 321 |
| 沙悟净 | 数学 | 12 | 321 |
| 沙悟净 | 语文 | 22 | 321 |
| 猪八戒 | 英语 | 11 | 321 |
| 猪八戒 | 数学 | 73 | 321 |
| 猪八戒 | 语文 | 10 | 321 |
| 孙悟空 | 英语 | 15 | 321 |
| 孙悟空 | 数学 | 12 | 321 |
| 孙悟空 | 语文 | 10 | 321 |
+-------+----------+--------+----------+
select name,subject,score,
sum(score) over() as sum1,
sum(score) over(partition by subject) as sum2,
sum(score) over(partition by subject order by score) as sum3,
-- 由起点到当前行的窗口聚合,和sum3一样
sum(score) over(partition by subject order by score rows between unbounded preceding and current row) as sum4,
-- 当前行和前面一行的窗口聚合
sum(score) over(partition by subject order by score rows between 1 preceding and current row) as sum5,
-- 当前行的前面一行到后面一行的窗口聚合 前一行+当前行+后一行
sum(score) over(partition by subject order by score rows between 1 preceding and 1 following) as sum6,
-- 当前行与后一行之和
sum(score) over(partition by subject order by score rows between current row and 1 following) as sum6,
-- 当前和后面所有的行
sum(score) over(partition by subject order by score rows between current row and unbounded following) as sum7
from t_fraction;
rows:行
unbounded preceding:起点
unbounded following:终点
n preceding:前 n 行
n following:后 n 行
current row:当前行
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
| name | subject | score | sum1 | sum2 | sum3 | sum4 | sum5 | sum6 | sum7 |
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
| 孙悟空 | 数学 | 12 | 359 | 185 | 12 | 12 | 12 | 31 | 185 |
| 沙悟净 | 数学 | 19 | 359 | 185 | 31 | 31 | 31 | 104 | 173 |
| 猪八戒 | 数学 | 73 | 359 | 185 | 104 | 104 | 92 | 173 | 154 |
| 唐玄奘 | 数学 | 81 | 359 | 185 | 185 | 185 | 154 | 154 | 81 |
| 猪八戒 | 英语 | 11 | 359 | 80 | 11 | 11 | 11 | 26 | 80 |
| 孙悟空 | 英语 | 15 | 359 | 80 | 26 | 26 | 26 | 49 | 69 |
| 唐玄奘 | 英语 | 23 | 359 | 80 | 49 | 49 | 38 | 69 | 54 |
| 沙悟净 | 英语 | 31 | 359 | 80 | 80 | 80 | 54 | 54 | 31 |
| 孙悟空 | 语文 | 10 | 359 | 94 | 10 | 10 | 10 | 31 | 94 |
| 唐玄奘 | 语文 | 21 | 359 | 94 | 31 | 31 | 31 | 53 | 84 |
| 沙悟净 | 语文 | 22 | 359 | 94 | 53 | 53 | 43 | 84 | 63 |
| 猪八戒 | 语文 | 41 | 359 | 94 | 94 | 94 | 63 | 63 | 41 |
+-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
rows必须跟在Order by 子句之后,对排序的结果进行限制,使用固定的行数来限制分区中的数据行数量。
OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。
CURRENT ROW:当前行
n PRECEDING:往前n行数据
n FOLLOWING:往后n行数据
UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点
LAG(col,n,default_val):往前第n行数据,col是列名,n是往上的行数,当第n行为null的时候取default_val
LEAD(col,n, default_val):往后第n行数据,col是列名,n是往下的行数,当第n行为null的时候取default_val
NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。
cume_dist(),计算某个窗口或分区中某个值的累积分布。假定升序排序,则使用以下公式确定累积分布:
小于等于当前值x的行数 / 窗口或partition分区内的总行数。其中,x 等于 order by 子句中指定的列的当前行中的值。
聚合开窗函数实战:
实战1:Hive用户购买明细数据分析
创建表和加载数据
name,orderdate,cost
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
建表加载数据
vim business.txt
create table business
(
name string,
orderdate string,
cost int
)ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/shujia/bigdata17/xiaohu/data/business.txt" into table business;
实战1需求:
需求1:查询在2017年4月份购买过的顾客及总人数
# 分析:按照日期过滤、分组count求总人数
select t1.name,t1.orderdate,count(1) over() as counts_04 from (select name,orderdate from business where month(orderdate)='04') t1;
需求2:查询顾客的购买明细及月购买总额
# 分析:按照顾客分组、sum购买金额
select name,orderdate,cost,sum(cost) over(partition by name,month(orderdate)) from business;
需求3:上述的场景,要将cost按照日期进行累加
# 分析:按照顾客分组、日期升序排序、组内每条数据将之前的金额累加
select name,orderdate,cost,sum(cost) over(partition by name order by orderdate rows between unbounded preceding and current row) from business;
需求4:查询顾客上次的购买时间
·# 分析:查询出明细数据同时获取上一条数据的购买时间(肯定需要按照顾客分组、时间升序排序)
select name,orderdate,cost,lag(orderdate,1) over(partition by name order by orderdate) as last_time from business;
需求5:查询前20%时间的订单信息
分析:按照日期升序排序、取前20%的数据
select t1.name,t1.orderdate,t1.cost from (select name,orderdate,cost,ntile(5) over(order by orderdate) as n from business) t1 where t1.n=1;
1.1.2 排序开窗函数(重点)
- RANK() 排序相同时会重复,总数不会变
- DENSE_RANK() 排序相同时会重复,总数会减少
- ROW_NUMBER() 会根据顺序计算
- PERCENT_RANK()计算给定行的百分比排名。可以用来计算超过了百分之多少的人(当前行的rank值-1)/(分组内的总行数-1)
select name,subject,
score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rnp,
percent_rank() over(partition by subject order by score) as percent_rank
from t_fraction;
select name,subject,score,
rank() over(order by score) as row_number,
percent_rank() over(partition by subject order by score) as percent_rank
from t_fraction;
实战2:Hive分析学生成绩信息
创建表语加载数据
name subject score
李毅 语文 87
李毅 数学 95
李毅 英语 68
黄仙 语文 94
黄仙 数学 56
黄仙 英语 84
小虎 语文 64
小虎 数学 86
小虎 英语 84
许文客 语文 65
许文客 数学 85
许文客 英语 78
建表加载数据
vim score.txt
create table score2
(
name string,
subject string,
score int
) row format delimited fields terminated by "\t";
load data local inpath '/shujia/bigdata17/xiaohu/data/score.txt' into table score;
需求1:每门学科学生成绩排名(是否并列排名、空位排名三种实现)
分析:学科分组、成绩降序排序、按照成绩排名
select name,subject,score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rmp
from
score;
需求2:每门学科成绩排名top 2的学生
select t1.name,t1.subject,t1.score from (select name,subject,score,row_number() over(partition by subject order by score desc) as rn from score2) t1 where t1.rn<3;
Hive 行转列
lateral view explode
create table testArray2(
name string,
weight array<string>
)row format delimited
fields terminated by '\t'
COLLECTION ITEMS terminated by ',';
小虎 "150","170","180"
火火 "150","180","190"
select name,col1 from testarray2 lateral view explode(weight) t1 as col1;
小虎 150
小虎 170
小虎 180
火火 150
火火 180
火火 190
select key from (select explode(map('key1',1,'key2',2,'key3',3)) as (key,value)) t;
key1
key2
key3
select name,col1,col2 from testarray2 lateral view explode(map('key1',1,'key2',2,'key3',3)) t1 as col1,col2;
小虎 key1 1
小虎 key2 2
小虎 key3 3
火火 key1 1
火火 key2 2
火火 key3 3
select name,pos,col1 from testarray2 lateral view posexplode(weight) t1 as pos,col1;
小虎 0 150
小虎 1 170
小虎 2 180
火火 0 150
火火 1 180
火火 2 190
Hive 列转行
// testLieToLine
name col1
小虎 150
小虎 170
小虎 180
火火 150
火火 180
火火 190
create table testLieToLine(
name string,
col1 int
)row format delimited
fields terminated by '\t';
select name,collect_list(col1) from testLieToLine group by name;
// 结果
小虎 ["150","180","190"]
火火 ["150","170","180"]
select t1.name
,collect_list(t1.col1)
from (
select name
,col1
from testarray2
lateral view explode(weight) t1 as col1
) t1 group by t1.name;
Hive自定义函数UserDefineFunction
UDF:一进一出(注意:该自定义函数只是临时的,只针对当前客户端有效,当客户退出之后,该自定义函数就会无效)
定义UDF函数要注意下面几点:(旧版本Hive重写)
- 继承
org.apache.hadoop.hive.ql.exec.UDF
- 重写
evaluate
(),这个方法不是由接口定义的,因为它可接受的参数的个数,数据类型都是不确定的。Hive会检查UDF,看能否找到和函数调用相匹配的evaluate()方法
- 创建maven项目,并加入依赖
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
打包的时候可能会出现错误
Could not transfer artifact org.pentaho:pentaho-aggdesigner-algorithm:pom:5.1.5-jhyde
解决方案:
在pom文件中修改hive-exec的配置
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<exclusions>
<!--排除pentaho-aggdesigner-algorithm依赖,不将它引入-->
<exclusion>
<groupId>org.pentaho</groupId>
<artifactId>pentaho-aggdesigner-algorithm</artifactId>
</exclusion>
</exclusions>
</dependency>
- 编写代码,继承org.apache.hadoop.hive.ql.exec.UDF,实现evaluate方法,在evaluate方法中实现自己的逻辑
- 打成jar包并上传至Linux虚拟机:利用xftp
- 在hive shell中,使用
add jar 路径
将jar包作为资源添加到hive客户端环境中
add jar /usr/local/soft/bigdata19/hive-bigdata19-1.0-SNAPSHOT.jar;
- 使用jar包资源注册一个临时函数,fxxx1是你的函数名,'MyUDF'是主类名
create temporary function shujia as 'com.shujia.custom.MyUDFdemo1';
- 使用函数名处理数据
select fxx1(name) as fxx_name from students limit 10;
#施笑槐$
#吕金鹏$
#单乐蕊$
#葛德曜$
#宣谷芹$
#边昂雄$
#尚孤风$
#符半双$
#沈德昌$
#羿彦昌$
案例2:转大写
函数加载方式
命令加载
这种加载只对本session有效
# 1、将项目打包上传服务器:将打好的jar包传到linux系统中。(不要打依赖)
# 进入到hive客户端,执行下面命令
hive> add jar /usr/local/soft/bigdata17/data/xiaohu/hadoop-mapreduce-1.0-SNAPSHOT.jar
# 2、创建一个临时函数名,要跟上面hive在同一个session里面:
hive> create temporary function toUP as 'com.shujia.testHiveFun.udf.FirstUDF';
3、检查函数是否创建成功
show functions;
4. 测试功能
select toUp('abcdef');
5. 删除函数
drop temporary function if exists toUp;
创建永久函数
主要思想是将提前写好的jar包上传到hdfs上面去,等退出客户端再进行重新连接的时候,就可以在hdfs上面找到这个jar包,从而解决了自定义函数只能使用一次的问题。**在navicat里面也会有对应的元数据信息。*,对应在FUNCS表里面。
(1)将jar上传HDFS:
hadoop fs -put hadoop-mapreduce-1.0-SNAPSHOT.jar /jar/
(2)在hive命令行中创建永久函数:
create function shujia as 'com.shujia.custom.MyUDFdemo1' using jar 'hdfs:/bigdata30/hive_jars/hive-udf-1.0.jar';
退出hive,再进入,执行测试:
删除永久函数,并检查:
5:新版本hive,写自定义函数
package com.shujia.custom;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
public class MyGenericUDFDemo1 extends GenericUDF {
/*
这个方法主要是对自定义的UDF函数进行初始化,目的是指定调用完函数返回的值的类型
需求:传入一个字符串,返回一个新的字符串
*/
@Override
public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
//使用PrimitiveObjectInspectorFactory工厂类,获取String类型的ObjectInspector TODO:要是返回的是int类型的,就调用int类型的ObjectInspector
return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
}
/**
* 该方法是自定义UDF的核心方法,目的是实现自定义的UDF的逻辑
* 是在initialize方法之后执行的
*
* deferredObjects将来会有多个参数,但是UDF函数只有一个参数,所以将传入的参数变成一个数组
* 所以deferredObjects[0]就是传入的第一个参数
*
* 新版本的hive只有一个evaluate函数,无法实现重载
*/
@Override
public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
String out = "";
DeferredObject deferredObject = deferredObjects[0];//这里的第一个参数可能是String类型的ename,也可能是int类型的sal
//deferredObject存储的是传入函数的元素
Object o = deferredObject.get();
//TODO 新版本的hive只有一个evaluate函数,无法实现重载,但是当要传入很多个的参数的时候,该怎么办呢,所以可以根据实际情况对传入的参数进行类型判断
//TODO 因为hive中的数据都是来自hdfs中的,读取的方式都是MR的方式读取的,所以这里面的数据类型判断应该用hdfs里面的数据类型
//TODO 例如,Text-String
if(o instanceof Text){
out = "数加:" + o;
}else if(o instanceof IntWritable){
IntWritable i = (IntWritable) o;
int sal = i.get();
if(sal<2000){
out="低薪";
}else if(sal<3000){
out="中等";
}else{
out = "高薪";
}
}
return out;
}
@Override
public String getDisplayString(String[] strings) {
return "这是我们自己使用新版本写法自定义的UDF函数";
}
}
UDTF:一进多出
UDTF是一对多的输入输出,实现UDTF需要完成下面步骤
M1001#xiaohu#S324231212,lkd#M1002#S2543412432,S21312312412#M1003#bfy
1001 xiaohu 324231212
1002 lkd 2543412432
1003 bfy 21312312412
继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF,
重写initlizer()、process()、close()。
执行流程如下:UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)。
初始化完成后,会调用process方法,真正的处理过程在process函数中,在process中,每一次forward()调用产生一行;如果产生多列可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数。
最后close()方法调用,对需要清理的方法进行清理。
"key1:value1,key2:value2,key3:value3"
key1 value1
key2 value2
key3 value3
方法一:使用 explode+split
方法二:自定UDTF
- 代码
- SQL
create temporary function my_udtf as 'com.shujia.testHiveFun.udtf.HiveUDTF';
select my_udtf("key1:value1,key2:value2,key3:value3");
字段:id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12 共13列
数据:
a,1,2,3,4,5,6,7,8,9,10,11,12
b,11,12,13,14,15,16,17,18,19,20,21,22
c,21,22,23,24,25,26,27,28,29,30,31,32
转成3列:id,hours,value
例如:
a,1,2,3,4,5,6,7,8,9,10,11,12
a,0时,1
a,2时,2
a,4时,3
a,6时,4
......
create table udtfData(
id string
,col1 string
,col2 string
,col3 string
,col4 string
,col5 string
,col6 string
,col7 string
,col8 string
,col9 string
,col10 string
,col11 string
,col12 string
)row format delimited fields terminated by ',';
代码:
添加jar资源:
add jar /usr/local/soft/HiveUDF2-1.0.jar;
注册udtf函数:
create temporary function my_udtf as 'MyUDTF';
SQL:
select id,hours,value from udtfData lateral view my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) t as hours,value ;
UDAF:多进一出
Hive Shell
第一种:
hive -e "select * from test1.students limit 10"
第二种:
hive -f hql文件路径
将HQL写在一个文件里,再使用 -f 参数指定该文件
连续登陆问题
在电商、物流和银行可能经常会遇到这样的需求:统计用户连续交易的总额、连续登陆天数、连续登陆开始和结束时间、间隔天数等
数据:
注意:每个用户每天可能会有多条记录
id datestr amount
1,2019-02-08,6214.23
1,2019-02-08,6247.32
1,2019-02-09,85.63
1,2019-02-09,967.36
1,2019-02-10,85.69
1,2019-02-12,769.85
1,2019-02-13,943.86
1,2019-02-14,538.42
1,2019-02-15,369.76
1,2019-02-16,369.76
1,2019-02-18,795.15
1,2019-02-19,715.65
1,2019-02-21,537.71
2,2019-02-08,6214.23
2,2019-02-08,6247.32
2,2019-02-09,85.63
2,2019-02-09,967.36
2,2019-02-10,85.69
2,2019-02-12,769.85
2,2019-02-13,943.86
2,2019-02-14,943.18
2,2019-02-15,369.76
2,2019-02-18,795.15
2,2019-02-19,715.65
2,2019-02-21,537.71
3,2019-02-08,6214.23
3,2019-02-08,6247.32
3,2019-02-09,85.63
3,2019-02-09,967.36
3,2019-02-10,85.69
3,2019-02-12,769.85
3,2019-02-13,943.86
3,2019-02-14,276.81
3,2019-02-15,369.76
3,2019-02-16,369.76
3,2019-02-18,795.15
3,2019-02-19,715.65
3,2019-02-21,537.71
建表语句
create table deal_tb(
id string
,datestr string
,amount string
)row format delimited fields terminated by ',';
计算逻辑
- 先按用户和日期分组求和,使每个用户每天只有一条数据
根据用户ID分组按日期排序,将日期和分组序号相减得到连续登陆的开始日期,如果开始日期相同说明连续登陆
datediff(string end_date,string start_date); 等于0说明连续登录
统计用户连续交易的总额、连续登陆天数、连续登陆开始和结束时间、间隔天数
- 结果
1 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
1 2019-02-08 2991.650 5 2019-02-12 2019-02-16 1
1 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1
1 2019-02-10 537.71 1 2019-02-21 2019-02-21 1
2 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
2 2019-02-08 3026.649 4 2019-02-12 2019-02-15 1
2 2019-02-10 1510.8 2 2019-02-18 2019-02-19 2
2 2019-02-11 537.71 1 2019-02-21 2019-02-21 1
3 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
3 2019-02-08 2730.04 5 2019-02-12 2019-02-16 1
3 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1
3 2019-02-10 537.71 1 2019-02-21 2019-02-21 1
作业:
复习员工案例
(1)题目1
sql:Hive实现按照指定格式输出每七天的消费平均数
输出格式:
2018-06-01~2018-06-07 12.29
...
2018-08-10~2018-08-16 80.67
数据如下:
2018/6/1,10
2018/6/2,11
2018/6/3,11
2018/6/4,12
2018/6/5,14
2018/6/6,15
2018/6/7,13
2018/6/8,37
2018/6/9,18
2018/6/10,19
2018/6/11,10
2018/6/12,11
2018/6/13,11
2018/6/14,12
2018/6/15,14
2018/6/16,15
2018/6/17,13
2018/6/18,17
2018/6/19,18
2018/6/20,19
2018/6/21,20
2018/6/22,21
2018/6/23,21
2018/6/24,22
2018/6/25,24
2018/6/26,25
2018/6/27,23
2018/6/28,27
2018/6/29,28
2018/6/30,29
2018/7/1,40
2018/7/2,41
2018/7/3,41
2018/7/4,42
2018/7/5,44
2018/7/6,45
2018/7/7,43
2018/7/8,47
2018/7/9,48
2018/7/10,49
2018/7/11,50
2018/7/12,51
2018/7/13,51
2018/7/14,52
2018/7/15,54
2018/7/16,55
2018/7/17,53
2018/7/18,57
2018/7/19,58
2018/7/20,59
2018/7/21,30
2018/7/22,31
2018/7/23,31
2018/7/24,32
2018/7/25,34
2018/7/26,35
2018/7/27,33
2018/7/28,37
2018/7/29,38
2018/7/30,39
2018/7/31,70
2018/8/1,71
2018/8/2,71
2018/8/3,72
2018/8/4,74
2018/8/5,75
2018/8/6,73
2018/8/7,77
2018/8/8,78
2018/8/9,79
2018/8/10,80
2018/8/11,81
2018/8/12,81
建表语句:
create table f
(
date_time string,
cost int
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
预习作业2:列出每个部门薪水前两名最高的人员名称以及薪水。(思考:用开窗函数解决)
题目(1):
select
t1.zhouqi
,round(avg(t1.cost),2) as avg_cost
from
(select
concat(date_add('2018-06-01',cast(floor(datediff(cast(regexp_replace(date_time,'/','-') as date) ,'2018-06-01')/7)*7 as int)),'~',date_add(date_add('2018-06-01',cast(floor(datediff(cast(regexp_replace(date_time,'/','-') as date) ,'2018-06-01')/7)*7 as int)),6)) as zhouqi
,cost
from
f
)
t1 group by t1.zhouqi;
题目(2)列出每个部门薪水前两名最高的人员名称以及薪水。(思考:用开窗函数解决)
select * from (select *,row_number() over(partition by deptno order by sal desc) from emp) t1 where row_number_window_0<3;
hive第三课:Hive函数学习的更多相关文章
- Hive扩展功能(三)--使用UDF函数将Hive中的数据插入MySQL中
软件环境: linux系统: CentOS6.7 Hadoop版本: 2.6.5 zookeeper版本: 3.4.8 主机配置: 一共m1, m2, m3这五部机, 每部主机的用户名都为centos ...
- Hive(三)Hive元数据信息对应MySQL数据库表
概述 Hive 的元数据信息通常存储在关系型数据库中,常用MySQL数据库作为元数据库管理.上一篇hive的安装也是将元数据信息存放在MySQL数据库中. Hive的元数据信息在MySQL数据中有57 ...
- Apache Hive (三)Hive元数据信息对应MySQL数据库表
转自:https://www.cnblogs.com/qingyunzong/p/8710356.html 概述 Hive 的元数据信息通常存储在关系型数据库中,常用MySQL数据库作为元数据库管理. ...
- 第三课 创建函数 - 从EXCEL读取 - 导出到EXCEL - 异常值 - Lambda函数 - 切片和骰子数据
第 3 课 获取数据 - 我们的数据集将包含一个Excel文件,其中包含每天的客户数量.我们将学习如何对 excel 文件进行处理.准备数据 - 数据是有重复日期的不规则时间序列.我们将挑战数 ...
- Python【第三课】 函数基础
本篇内容 函数基本语法及特性 嵌套函数 递归函数 匿名函数 高阶函数 内置函数 1.函数的基本语法及特性 1.1 函数概念 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提 ...
- Hive学习之路 (三)Hive元数据信息对应MySQL数据库表
概述 Hive 的元数据信息通常存储在关系型数据库中,常用MySQL数据库作为元数据库管理.上一篇hive的安装也是将元数据信息存放在MySQL数据库中. Hive的元数据信息在MySQL数据中有57 ...
- hive自定义函数学习
1介绍 Hive自定义函数包括三种UDF.UDAF.UDTF UDF(User-Defined-Function) 一进一出 UDAF(User- Defined Aggregation Funcat ...
- Hive 学习之路(三)—— Hive CLI和Beeline命令行的基本使用
一.Hive CLI 1.1 Help 使用hive -H或者 hive --help命令可以查看所有命令的帮助,显示如下: usage: hive -d,--define <key=value ...
- hadoop入门级总结三:hive
认识hive Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务运行 Hive是建立在 ...
- Hive入门笔记---2.hive函数大全
Hive函数大全–完整版 现在虽然有很多SQL ON Hadoop的解决方案,像Spark SQL.Impala.Presto等等,但就目前来看,在基于Hadoop的大数据分析平台.数据仓库中,Hiv ...
随机推荐
- spannerlib优雅的go异常处理
蹩脚的go 异常处理 一般写go的人,如果他不是写算法,正常写业务代码的话,可能都会为优雅的异常处理而烦恼,因为脑子抽筋的go设计者们,总是感觉语法糖是一种很低级的东西.但是在我们大多数公司的业务逻辑 ...
- 如何禁用IntelliJ IDEA的LightEdit模式
更新pycharm之后发现有了个新功能,默认打开文件的时候会单独打开一个窗口,以文本编辑的模式打开,而不是用项目模式.这种打开方式被称为LightEdit Mode.效果如下, 可以注意到窗口很简洁, ...
- sqli-labs-master 第二,三,四关
第二关: 判断注入类型:http://192.168.65.130/sqli-labs-master/Less-2/?id=1 --+ 原因:$sql="SELECT * FROM user ...
- Gem离线包安装
Gem离线包安装 项目环境 以 rest-client 为例 本地如果是rails项目环境: ruby '2.7.0' gem 'rails', '~> 6.0.3', '>= 6.0.3 ...
- ERROR: Error installing mysql2: ERROR: Failed to build gem native extension [@Ubuntu 15.04]
参考文章: https://blog.csdn.net/a60919820/article/details/101847890 安装mysql 参考:https://www.cnblogs.com/h ...
- 解决HtmlUnit执行JS报错提示ScriptException
问题描述 HtmlUnit作为一款比Selenium更轻量的HeadLess的Java版本浏览器模拟器,不需要在服务器上安装部署浏览器及其Driver程序. 但是,众所周知,HtmlUnit对JS脚本 ...
- C语言:汉诺塔问题(Hanoi Tower)------递归算法
汉诺塔问题是一个经典的问题.汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆 ...
- AIRIOT答疑第2期|如何使用物联网平台的数据采集与控制引擎?
任性用! 作为AIRIOT物联网低代码平台的五大核心能力引擎之一,数据采集与控制引擎具备极强的系统集成能力,提供丰富的接口,具备海量工业设备驱动库,分布式采集,稳定性高,实现快速的设备接入.报警. ...
- kubernetes之python调用
安装 sudo pip3 install kubernetes 认证 首先引入SDK支持库.然后将 ~/.kube 的config文件的内容复制到本地目录,保存为文件kubeconfig.yaml,然 ...
- 基于webapi的websocket聊天室(四)
上一篇实现了多聊天室.这一片要继续改进的是实现收发文件,以及图片显示. 效果 问题 websocket本身就是二进制传输.文件刚好也是二进制存储的. 文件本身的传输问题不太,但是需要传输文件元数据,比 ...