1.开窗函数查询
-
窗口函数通常是分析人员使用 hive ql 进行一些复杂逻辑计算时使用的特殊函数,其中 over() 通常与聚合函数共同使用,比如 count()、sum()、min()、max()、avg() 等。
-
over() 具有一定的窗口语义,如:OVER(ROWS ((CURRENT ROW) | (UNBOUNDED) PRECEDING) AND (UNBOUNDED |(CURRENT ROW) ) FOLLOWING )
-
over() 直接使用时,通常是指定全量数据,当我们想要按某列的不同值进行窗口划分时,可以在 over() 中加入 partition by 语句。
hive 常用开窗函数说明
over():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化
current row:当前行
preceding n:往前n行数据
following n:往后n行数据
unbounded:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点
lag(col,n):往前第n行数据
lead(col,n):往后第n行数据
ntile(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。
2.Hive 开窗函数代码示例1:
2.1 数据准备: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
2.2 环境准备
// 创建本地business.txt,导入数据
[luomk@hadoop102 datas]$ vi business.txt
// 创建hive表并导入数据
create table business(
name string,
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',’;
load data local inpath "/opt/module/datas/business.txt" into table business;
2.3 需求及实现
• 查询在2017年4月份购买过的顾客及总人数
• 查询顾客的购买明细及月购买总额
• 上述的场景,要将cost按照日期进行累加
• 查询顾客上次的购买时间 • 查询前20%时间的订单信息
// 查询在2017年4月份购买过的顾客及总次数
select name,count(*) over (partition by name)
from business
where substring(orderdate,1,7) = '2017-04’;
// 查询顾客的购买明细及月购买总额
select name,orderdate,cost,sum(cost) over(partition by month(orderdate)) from
business;
// 上述的场景,要将cost按照日期进行累加
select name,orderdate,cost,
sum(cost) over() as sample1,--所有行相加
sum(cost) over(partition by name) as sample2,--按name分组,组内数据相加
sum(cost) over(partition by name order by orderdate) as sample3,--按name分组,组内数据累加
sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row ) as sample4 ,--和sample3一样,由起点到当前行的聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and current row) as sample5, --当前行和前面一行做聚合
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING ) as sample6,--当前行和前边一行及后面一行
sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --当前行及后面所有行
from business;
// 查看顾客上次的购买时间
select name,orderdate,cost,
lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1, lag(orderdate,2) over (partition by name order by orderdate) as time2
from business;
// 查询前20%时间的订单信息
select * from (
select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
from business
) t
where sorted = 1;
3.
Hive 开窗函数代码示例2:
创建测试表并加载简单的示例数据进行演示
hive> create table recommend.test_window(logday string, userid string, score int)
> row format delimited
> Fields terminated by ',’;
logday userid score
20191020 11111 85
20191020 22222 83
20191020 33333 86
20191021 11111 87
20191021 22222 65
20191021 33333 98
20191022 11111 67
20191022 22222 34
20191022 33333 88
20191023 11111 99
20191023 22222 33
示例 1: 简单使用 over() 函数进行数据统计, 统计每个用户及表中数据的总数。
hive> select logday, userid, score, count(*) over() as total
> from recommend.test_window;
OK
logday userid score total
20191023 22222 33 11
20191023 11111 99 11
20191022 33333 88 11
20191022 22222 34 11
20191022 11111 67 11
20191021 33333 98 11
20191021 22222 65 11
20191021 11111 87 11
20191020 33333 86 11
20191020 22222 83 11
20191020 11111 85 11
//这里使用 over() 与 select count(*) 有相同的作用,好处就是,在需要列出所有列值时不用再进行一次关联。
示例 2: 当想要对每天的数据进行统计时,可以使用 partition by 按日期列对数据进行分区处理,如:over(partition by logday)
hive> select logday, userid, count(userid) over(partition by logday) as total
> from recommend.test_window;
OK
logday userid total
20191020 33333 3
20191020 22222 3
20191020 11111 3
20191021 33333 3
20191021 22222 3
20191021 11111 3
20191022 33333 3
20191022 22222 3
20191022 11111 3
20191023 22222 2
20191023 11111 2
// 这种用法与 select logday, count(userid) from recommend.test_window group by logday 具有相同的效果,但是当想要得到 userid 信息时,这种用法的优势就很明显。
示例 3: 下面我们想要得到从第一天到现在的所有 score 大于80分的用户总数,此时简单的分区不能满足需求,需要将 order by 和 窗口定义结合使用。
hive>
> select logday,
> count(userid) over(order by logday rows between unbounded preceding and current row)
> from recommend.test_window
> where score > 80;
OK
20191020 1
20191020 2
20191020 3
20191021 4
20191021 5
20191022 6
20191023 7
//通过 over() 计算出按日期的累加值后,然后去每天的最大值就是需要的总的累加值。
示例 4:计算每个用户到当前日期分数大于80的天数。
hive> select userid, logday, score, count(case when score>=80 then userid else null end) over(partition by userid order by logday rows between unbounded preceding and current row) as total
> from recommend.test_window
> order by logday, userid;
useri logday score total
11111 20191020 85 1
22222 20191020 83 1
33333 20191020 86 1
11111 20191021 87 2
22222 20191021 65 1
33333 20191021 98 2
11111 20191022 67 2
22222 20191022 34 1
33333 20191022 88 3
11111 20191023 99 3
22222 20191023 33 1
扩展
-
分区语句 partition by 除了这里使用的单列分区外,还可以使用多列分区。事实上,这里的分区跟创建 hive 分区表有异曲同工之妙。
-
窗口的划分除了上面使用的 rows between unbounded preceding and current row 之外,还有其他的使用场景,如:
ROWS BETWEEN CURRENT ROW AND n FOLLOWING:从当前行到随后的n行 ROWS BETWEEN n PRECEDING AND CURRENT ROW:从前n行到当前行 ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING: 从当前行到结尾行