hive之窗口函数理解与实践

快过年了,总算没那么忙了,可以完善一下这篇文章了。之前只能说是备忘罢了,很多细节没说清楚。

首先,我们要知道什么是窗口子句:

需要指定一个窗口的边界,语法是这样的:

ROWS betweenCURRENT ROW | UNBOUNDED PRECEDING | [num] PRECEDING AND  UNBOUNDED FOLLOWING | [num] FOLLOWING| CURRENT ROW

RANGE between [num] PRECEDING  AND [num]FOLLOWING

如下图:



ROWS是物理窗口,从行数上控制窗口的尺寸的;

RANGE是逻辑窗口,从列值上控制窗口的尺寸。这个比较难理解,但说白了就简单了,具体解释如下面栗子1.

结合order by子句使用,如果在order by子句后面没有指定窗口子句,则默认为:range between unbounded preceding and current row

------------------------------------------------------------

rt_data表存放了当天每半小时的店铺销售数据

字段stat_date格式yyMMddHHmm

------------------------------------------------------------

1.统计截止到当前时间段的店铺累计销售金额

select shop_id, stat_date, ordamt, sum(ordamt) over(partition by shop_id order by stat_date) 
from rt_data 
where dt = '2015-01-11' and shop_id = 10026;

10026	201501120030	5170	5170
10026	201501120100	5669	10839
10026	201501120130	2396	13235
10026	201501120200	1498	14733
10026	201501120230	1997	16730
10026	201501120300	1188	17918
10026	201501120330	598	18516
10026	201501120400	479	18995
10026	201501120430	1587	20582
10026	201501120530	799	21381

这里order by 后面省去了窗口子句,还原起来就是order by stat_date range between unbounded preceding and current row. 这是什么意思?

就是先按stat_date排序,窗口就是比当前stat_date小的行到当前stat_date的行。

其实,这里写成order by stat_date rows between unbounded preceding and current row是一样的。

2.统计每个时间段的销售占比

select shop_id, stat_date, ordamt, ordamt / sum(ordamt) over(partition by shop_id) 
from rt_data 
where dt = '2015-01-11' and shop_id = 10026
order by stat_date;

10026	201501120900	5406	0.014227
10026	201501120930	13098	0.034471
10026	201501121000	15679	0.041263
10026	201501121030	12134	0.031934
10026	201501121100	26259	0.069107
10026	201501121130	16516	0.043466
10026	201501121200	20127	0.052969

partition by之后没有使用order by,窗口大小默认就是整个分组。

3.找出2点的销售金额及前半小时的销售金额和后1个小时的销售金额

select * from ( 
    select 
        shop_id, 
        stat_date,
        ordamt, 
        lag(stat_date,1) over(partition by shop_id order by stat_date), 
        lag(ordamt,1) over(partition by shop_id order by stat_date), 
        lead(stat_date,2) over(partition by shop_id order by stat_date),
        lead(ordamt,2) over(partition by shop_id order by stat_date) 
    from rt_data 
    where dt = '2015-01-11' and shop_id = 10026 
) t
where stat_date = 201501120200;

10026	201501120200	1498	201501120130	2396	201501120300	1188

lag(field, N)是取前N行的值,lead(field, N)是取后N行的值。

4.按照销售金额进行排名,金额最大的排最前(limit可以取topn的数)

select shop_id, stat_date, ordamt, dense_rank() over(partition by shop_id order by ordamt desc) 
from rt_data 
where dt = '2015-01-11' and shop_id = 10026;

10026	201501121100	26259.0	1
10026	201501121200	20127.0	2
10026	201501121300	18138.0	3
10026	201501121130	16516.0	4
10026	201501121400	15956.0	5
10026	201501121000	15679.0	6
10026	201501122200	14290.0	7
10026	201501121430	14203.0	8
10026	201501121330	13290.0	9
10026	201501120930	13098.0	10

dense_rank和rank都是排名函数,区别在于dense_rank是连续排名,rank遇到排名并列时,下一列排名跳空。

percent_rank,介于0和1直接的小数形式表示,计算方法是(rank - 1) / (n-1),其中rank为行的序号,n为组的行数,这个暂时不知道有什么地方可以运用,欢迎指导。

5.按销售金额排序,取出前20%的时间段和相应金额

select * from (
    select shop_id, stat_date, ordamt, ntile(5) over(partition by shop_id order by ordamt desc) sorted 
    from rt_data 
    where dt = '2015-01-11' and shop_id = 10026 
) t 
where sorted = 1;

10026	201501121100	26259.0	1
10026	201501121200	20127.0	1
10026	201501121300	18138.0	1
10026	201501121130	16516.0	1
10026	201501121400	15956.0	1
10026	201501121000	15679.0	1
10026	201501122200	14290.0	1
10026	201501121430	14203.0	1
10026	201501121330	13290.0	1
NTILE这个很强大,以前要获取一定比例的数据是非常困难的,NTILE就是把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。

---------------------------------------------------------------------

over语句还可以独立出来,用window重写,但需要注意的是,如下sort by使用了多个字段,如果用range指定窗口的话会出错,需要用rows来指定窗口,因为range是对列的比较,不支持多列比较。

select shop_id, stat_date, ordamt, sum(ordamt) over win as t
from rt_data 
where dt = '2015-01-11' and shop_id = 10026
window win as (distribute by shop_id sort by shop_id, ordamt desc rows between unbounded preceding and current row);


评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值