Hive零基础从入门到实战 进阶篇(十六) HiveQL:开窗函数(组内排序)

目录

 

前言

1. 组内排序的开窗函数表

2. 函数功能演示

2.1 row_number()

2.1.1 应用场景1:生成排序后的唯一序号

2.1.2 应用场景2:取top n

2.1.3 应用场景3:每个分组内取出n个随机值

2.2 rank()

2.3 dense_rank()


 

前言

上篇博客介绍了Hive中用于累计统计的开窗函数,本文接续上文介绍第二种:用于组内排序的开窗函数。用于组内排序的开窗函数使用频率远高于其他开窗函数,因为在工作中应用场景更多,比如分组排序、取每个分组内的Top n、用户行为轨迹追踪、组内随机抽样等等。下面我们对这类函数来做一个详细介绍。

 

1. 组内排序的开窗函数表

函数名 描述
row_number() 

生成数据项在分组中的排名,排名即便相等也不会有并列排名,相同排名随机排序。例:1,2,3,4,5

rank()

生成数据项在分组中的排名,排名相等时会产生并列排名,然后会在名次中留下空位。例:1,2,2,4,5

dense_rank()

生成数据项在分组中的排名,排名相等时会产生并列排名,然后在名次中不会留下空位。例:1,2,2,3,4

上述三个函数使用时依旧是后面+开窗函数的固定写法:

over(partition by 列名1,列名2 …… order by 列名3,列名4 …… [desc])

 

2. 函数功能演示

数据准备:

新建test.txt文件,输入如下的三列数据,以空格分隔。第一列是月份,第二列代表商铺名称,第三列代表该商铺该月营业额(万元)。

[root@hadoop ~]# vim test.txt 

2019-01 a 4
2019-01 b 3
2019-01 c 3
2019-01 d 2
2019-01 e 1
2019-02 a 1
2019-02 b 2
2019-02 c 3
2019-02 d 3
2019-02 e 4

在hive中新建表temp_test10,将test文件中的数据插入,查看数据。

CREATE TABLE temp_test10 (
      month STRING comment '月份'
      ,shop STRING comment '商铺名称'
      ,money STRING comment '营业额(万元)'
      ) row format delimited fields terminated BY ' ';
 
 
load data local inpath '/root/test.txt' into table temp_test10;
 
select * from temp_test10;
 
temp_test10.month	temp_test10.shop	temp_test10.money
2019-01	a	4
2019-01	b	3
2019-01	c	3
2019-01	d	2
2019-01	e	1
2019-02	a	1
2019-02	b	2
2019-02	c	3
2019-02	d	3
2019-02	e	4

 

2.1 row_number()

row_number()会生成数据项在分组中的排名,排名即便相等也不会有并列排名,相同排名随机排序。

2.1.1 应用场景1:生成排序后的唯一序号

举例:首先按照月份进行分组,然后每个组内按照营业额从大到小排序,为组内每一行数据得到一个唯一序号。

SELECT month
      ,shop
      ,MONEY
      ,row_number() OVER (
            PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序
            ) AS rk  --生成的排序序号
FROM temp_test10


结果:

month	shop	money	rk
2019-01	a	4	1
2019-01	c	3	2
2019-01	b	3	3
2019-01	d	2	4
2019-01	e	1	5
2019-02	e	4	1
2019-02	d	3	2
2019-02	c	3	3
2019-02	b	2	4
2019-02	a	1	5

2.1.2 应用场景2:取top n

举例:取出1月和2月每个月营业额排名前3的店铺及营业额。

使用子查询取出rk<=3的数据即可

SELECT *
FROM (
      SELECT month
            ,shop
            ,MONEY
            ,row_number() OVER (
                  PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序
                  ) AS rk
      FROM temp_test10
      ) a
WHERE rk <= 3;

结果:
a.month	a.shop	a.money	a.rk
2019-01	a	4	1
2019-01	c	3	2
2019-01	b	3	3
2019-02	e	4	1
2019-02	d	3	2
2019-02	c	3	3

如果只有一个分组,那么可以省略partition by,比如只取出1月营业额排名前3的店铺及营业额。

SELECT *
FROM (
      SELECT month
            ,shop
            ,MONEY
            ,row_number() OVER (
                  ORDER BY MONEY DESC --按照营业额从大到小排序
                  ) AS rk
      FROM temp_test10
      WHERE month = '2019-01'
      ) a
WHERE rk <= 3;

结果:
a.month	a.shop	a.money	a.rk
2019-01	a	4	1
2019-01	c	3	2
2019-01	b	3	3

2.1.3 应用场景3:每个分组内取出n个随机值

row_number()配合rand()函数即可实现每个分组内取出n个随机值的需求。

举例:每个月随机抽取两家店铺

SELECT *
FROM (
      SELECT month
            ,shop
            ,MONEY
            ,row_number() OVER (
                  PARTITION BY month ORDER BY rand(1) --可以使用任意数作为种子进行随机排序,也可以不填,直接使用rand()
                  ) AS rk
      FROM temp_test10
      ) a
WHERE rk <= 2; --限制rk来取出n个随机值

结果:
a.month	a.shop	a.money	a.rk
2019-01	c	3	1
2019-01	d	2	2
2019-02	a	1	1
2019-02	e	4	2

2.2 rank()

rank()可以生成数据项在分组中的排名,排名相等时会产生并列排名,然后会在名次中留下空位。应用场景不多,很少需要使用,了解即可。

举例:首先按照月份进行分组,然后每个组内按照营业额从大到小排序,生成排名,并列排名后留下空位。

SELECT month
      ,shop
      ,MONEY
      ,rank() OVER (
            PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序
            ) AS rk  --生成的排序序号
FROM temp_test10;


结果:

month	shop	money	rk
2019-01	a	4	1
2019-01	c	3	2
2019-01	b	3	2
2019-01	d	2	4
2019-01	e	1	5
2019-02	e	4	1
2019-02	d	3	2
2019-02	c	3	2
2019-02	b	2	4
2019-02	a	1	5

 

2.3 dense_rank()

dense_rank()可以生成数据项在分组中的排名,排名相等时会产生并列排名,但不会在名次中留下空位。应用场景也不多,很少需要使用,了解即可。

举例:首先按照月份进行分组,然后每个组内按照营业额从大到小排序,生成排名,并列排名后不要留下空位。

SELECT month
      ,shop
      ,MONEY
      ,dense_rank() OVER (
            PARTITION BY month ORDER BY MONEY DESC --按照月份进行分组,然后每个组内按照营业额从大到小排序
            ) AS rk  --生成的排序序号
FROM temp_test10;


结果:

month	shop	money	rk
2019-01	a	4	1
2019-01	c	3	2
2019-01	b	3	2
2019-01	d	2	3
2019-01	e	1	4
2019-02	e	4	1
2019-02	d	3	2
2019-02	c	3	2
2019-02	b	2	3
2019-02	a	1	4

 

 


能看到这里的同学,就右上角点个赞吧,3Q~

你可能感兴趣的:(Hive零基础从入门到实战 进阶篇(十六) HiveQL:开窗函数(组内排序))