聊聊Hive常见的分析函数

大数据
dense_rank函数的功能与rank函数类似,dense_rank函数在生成序号时是连续的,而rank函数生成的序号有可能不连续。当出现名次相同时,则排名序号也相同。而下一个排名的序号与上一个排名序号是连续的。

[[402112]]

本文转载自微信公众号「大数据技术与数仓」,作者西贝。转载本文请联系大数据技术与数仓公众号。

 1.基本语法

  1. Function (arg1,..., argn) OVER ([PARTITION BY <...>] [ORDER BY <....>] 
  2. [<window_expression>]) 

Function (arg1,..., argn) 可以是下面的四类函数:

  • Aggregate Functions: 聚合函数,比如:sum(...)、 max(...)、min(...)、avg(...)等
  • Sort Functions: 数据排序函数, 比如 :rank(...)、row_number(...)等
  • Analytics Functions: 统计和比较函数, 比如:lead(...)、lag(...)、 first_value(...)等

2.数据准备

样例数据

  1. [职工姓名|部门编号|职工ID|工资|岗位类型|入职时间] 
  2. Michael|1000|100|5000|full|2014-01-29 
  3. Will|1000|101|4000|full|2013-10-02 
  4. Wendy|1000|101|4000|part|2014-10-02 
  5. Steven|1000|102|6400|part|2012-11-03 
  6. Lucy|1000|103|5500|full|2010-01-03 
  7. Lily|1001|104|5000|part|2014-11-29 
  8. Jess|1001|105|6000|part|2014-12-02 
  9. Mike|1001|106|6400|part|2013-11-03 
  10. Wei|1002|107|7000|part|2010-04-03 
  11. Yun|1002|108|5500|full|2014-01-29 
  12. Richard|1002|109|8000|full|2013-09-01 

建表语句:

  1. CREATE TABLE IF NOT EXISTS employee ( 
  2. name string, 
  3. dept_num int
  4. employee_id int
  5. salary int
  6. type string, 
  7. start_date date 
  8. ROW FORMAT DELIMITED 
  9. FIELDS TERMINATED BY '|' 
  10. STORED as TEXTFILE; 

加载数据

  1. load data local inpath '/opt/datas/data/employee_contract.txt' into table employee; 

3.窗口聚合函数

(1)查询姓名、部门编号、工资以及部门人数

  1. select  
  2.     name
  3.     dept_num as deptno , 
  4.     salary, 
  5.     count(*) over (partition by dept_num) as cnt  
  6. from employee ; 

结果输出:

  1. name    deptno  salary  cnt 
  2. Lucy    1000    5500    5 
  3. Steven  1000    6400    5 
  4. Wendy   1000    4000    5 
  5. Will    1000    4000    5 
  6. Michael 1000    5000    5 
  7. Mike    1001    6400    3 
  8. Jess    1001    6000    3 
  9. Lily    1001    5000    3 
  10. Richard 1002    8000    3 
  11. Yun     1002    5500    3 
  12. Wei     1002    7000    3 

(2)查询姓名、部门编号、工资以及每个部门的总工资,部门总工资按照降序输出

  1. select  
  2.     name , 
  3.     dept_num as deptno, 
  4.     salary, 
  5.     sum(salary) over (partition by dept_num order by dept_num) as sum_dept_salary  
  6. from employee  
  7. order by sum_dept_salary desc

结果输出:

  1. name    deptno  salary  sum_dept_salary 
  2. Michael 1000    5000    24900 
  3. Will    1000    4000    24900 
  4. Wendy   1000    4000    24900 
  5. Steven  1000    6400    24900 
  6. Lucy    1000    5500    24900 
  7. Wei     1002    7000    20500 
  8. Yun     1002    5500    20500 
  9. Richard 1002    8000    20500 
  10. Lily    1001    5000    17400 
  11. Jess    1001    6000    17400 
  12. Mike    1001    6400    17400 

4.窗口排序函数

简介

窗口排序函数提供了数据的排序信息,比如行号和排名。在一个分组的内部将行号或者排名作为数据的一部分进行返回,最常用的排序函数主要包括:

row_number:根据具体的分组和排序,为每行数据生成一个起始值等于1的唯一序列数

rank:对组中的数据进行排名,如果名次相同,则排名也相同,但是下一个名次的排名序号会出现不连续。比如查找具体条件的topN行

dense_rank:dense_rank函数的功能与rank函数类似,dense_rank函数在生成序号时是连续的,而rank函数生成的序号有可能不连续。当出现名次相同时,则排名序号也相同。而下一个排名的序号与上一个排名序号是连续的。

percent_rank:排名计算公式为:(current rank - 1)/(total number of rows - 1)

ntile:将一个有序的数据集划分为多个桶(bucket),并为每行分配一个适当的桶数。它可用于将数据划分为相等的小切片,为每一行分配该小切片的数字序号。

(1)查询姓名、部门编号、工资、排名编号(按工资的多少排名)

  1. select  
  2.    name , 
  3.    dept_num as dept_no , 
  4.    salary, 
  5.    row_number() over (order by salary desc ) rnum  
  6. from employee; 

结果输出:

  1. name    dept_no salary  rnum 
  2. Richard 1002    8000    1 
  3. Wei     1002    7000    2 
  4. Mike    1001    6400    3 
  5. Steven  1000    6400    4 
  6. Jess    1001    6000    5 
  7. Yun     1002    5500    6 
  8. Lucy    1000    5500    7 
  9. Lily    1001    5000    8 
  10. Michael 1000    5000    9 
  11. Wendy   1000    4000    10 
  12. Will    1000    4000    11 

(2)查询每个部门工资最高的两个人的信息(姓名、部门、薪水)

  1. select  
  2.    name
  3.    dept_num, 
  4.    salary  
  5. from 
  6.  select name , 
  7.    dept_num , 
  8.    salary, 
  9.    row_number() over (partition by dept_num order by salary desc ) rnum  
  10.  from employee) t1 
  11.  where rnum <= 2; 

结果输出:

  1. name    dept_num        salary 
  2. Steven  1000    6400 
  3. Lucy    1000    5500 
  4. Mike    1001    6400 
  5. Jess    1001    6000 
  6. Richard 1002    8000 
  7. Wei     1002    7000 

(3)查询每个部门的员工工资排名信息

  1. select 
  2.  name , 
  3.  dept_num as dept_no , 
  4.  salary,row_number() over (partition by dept_num order by salary desc ) rnum  
  5. from employee; 

结果输出:

  1. name    dept_no salary  rnum 
  2. Steven  1000    6400    1 
  3. Lucy    1000    5500    2 
  4. Michael 1000    5000    3 
  5. Wendy   1000    4000    4 
  6. Will    1000    4000    5 
  7. Mike    1001    6400    1 
  8. Jess    1001    6000    2 
  9. Lily    1001    5000    3 
  10. Richard 1002    8000    1 
  11. Wei     1002    7000    2 
  12. Yun     1002    5500    3 

(4)使用rank函数进行排名

  1. select 
  2.   name
  3.   dept_num, 
  4.   salary, 
  5.   rank() over (order by salary desc) rank 
  6. from employee; 

结果输出:

  1. name    dept_num        salary  rank 
  2. Richard 1002    8000    1 
  3. Wei     1002    7000    2 
  4. Mike    1001    6400    3 
  5. Steven  1000    6400    3 
  6. Jess    1001    6000    5 
  7. Yun     1002    5500    6 
  8. Lucy    1000    5500    6 
  9. Lily    1001    5000    8 
  10. Michael 1000    5000    8 
  11. Wendy   1000    4000    10 
  12. Will    1000    4000    10 

(5)使用dense_rank进行排名

  1. select 
  2.   name
  3.   dept_num, 
  4.   salary, 
  5.   dense_rank() over (order by salary desc) rank 
  6. from employee; 

结果输出:

  1. name    dept_num        salary  rank 
  2. Richard 1002    8000    1 
  3. Wei     1002    7000    2 
  4. Mike    1001    6400    3 
  5. Steven  1000    6400    3 
  6. Jess    1001    6000    4 
  7. Yun     1002    5500    5 
  8. Lucy    1000    5500    5 
  9. Lily    1001    5000    6 
  10. Michael 1000    5000    6 
  11. Wendy   1000    4000    7 
  12. Will    1000    4000    7 

(6)使用percent_rank()进行排名

  1. select 
  2.   name
  3.   dept_num, 
  4.   salary, 
  5.   percent_rank() over (order by salary desc) rank 
  6. from employee; 

结果输出:

  1. name    dept_num        salary  rank 
  2. Richard 1002    8000    0.0 
  3. Wei     1002    7000    0.1 
  4. Mike    1001    6400    0.2 
  5. Steven  1000    6400    0.2 
  6. Jess    1001    6000    0.4 
  7. Yun     1002    5500    0.5 
  8. Lucy    1000    5500    0.5 
  9. Lily    1001    5000    0.7 
  10. Michael 1000    5000    0.7 
  11. Wendy   1000    4000    0.9 
  12. Will    1000    4000    0.9 

(7)使用ntile进行数据分片排名

  1. SELECT 
  2. name
  3. dept_num as deptno, 
  4. salary, 
  5. ntile(4) OVER(ORDER BY salary descas ntile 
  6. FROM employee; 

结果输出:

  1. name    deptno  salary  ntile 
  2. Richard 1002    8000    1 
  3. Wei     1002    7000    1 
  4. Mike    1001    6400    1 
  5. Steven  1000    6400    2 
  6. Jess    1001    6000    2 
  7. Yun     1002    5500    2 
  8. Lucy    1000    5500    3 
  9. Lily    1001    5000    3 
  10. Michael 1000    5000    3 
  11. Wendy   1000    4000    4 
  12. Will    1000    4000    4 

从 Hive v2.1.0开始, 支持在OVER语句里使用聚集函数,比如

  1. SELECT 
  2.   dept_num, 
  3.   row_number() OVER (PARTITION BY dept_num ORDER BY sum(salary)) as rk 
  4. FROM employee 
  5. GROUP BY dept_num; 

结果输出:

  1. dept_num        rk 
  2. 1000    1 
  3. 1001    1 
  4. 1002    1 

5.窗口分析函数

常用的分析函数主要包括:

  • cume_dist

如果按升序排列,则统计:小于等于当前值的行数/总行数(number of rows ≤ current row)/(total number of rows)。如果是降序排列,则统计:大于等于当前值的行数/总行数。比如,统计小于等于当前工资的人数占总人数的比例 ,用于累计统计。

  • lead(value_expr[,offset[,default]])

用于统计窗口内往下第n行值。第一个参数为列名,第二个参数为往下第n行(可选,默认为1),第三个参数为默认值(当往下第n行为NULL时候,取默认值,如不指定,则为NULL

  • lag(value_expr[,offset[,default]]):

与lead相反,用于统计窗口内往上第n行值。第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL)

  • first_value: 取分组内排序后,截止到当前行,第一个值
  • last_value

取分组内排序后,截止到当前行,最后一个值

  • (1)统计小于等于当前工资的人数占总人数的比例
  1. SELECT 
  2.  name
  3.  dept_num as deptno, 
  4.  salary, 
  5.  cume_dist() OVER (ORDER BY salary) as cume 
  6. FROM employee; 

结果输出:

  1. name    deptno  salary  cume 
  2. Wendy   1000    4000    0.18181818181818182 
  3. Will    1000    4000    0.18181818181818182 
  4. Lily    1001    5000    0.36363636363636365 
  5. Michael 1000    5000    0.36363636363636365 
  6. Yun     1002    5500    0.5454545454545454 
  7. Lucy    1000    5500    0.5454545454545454 
  8. Jess    1001    6000    0.6363636363636364 
  9. Mike    1001    6400    0.8181818181818182 
  10. Steven  1000    6400    0.8181818181818182 
  11. Wei     1002    7000    0.9090909090909091 
  12. Richard 1002    8000    1.0 

(2)统计大于等于当前工资的人数占总人数的比例

  1. SELECT 
  2.  name
  3.  dept_num as deptno, 
  4.  salary, 
  5.  cume_dist() OVER (ORDER BY salary descas cume 
  6. FROM employee; 

结果输出:

  1. name    deptno  salary  cume 
  2. Richard 1002    8000    0.09090909090909091 
  3. Wei     1002    7000    0.18181818181818182 
  4. Mike    1001    6400    0.36363636363636365 
  5. Steven  1000    6400    0.36363636363636365 
  6. Jess    1001    6000    0.45454545454545453 
  7. Yun     1002    5500    0.6363636363636364 
  8. Lucy    1000    5500    0.6363636363636364 
  9. Lily    1001    5000    0.8181818181818182 
  10. Michael 1000    5000    0.8181818181818182 
  11. Wendy   1000    4000    1.0 
  12. Will    1000    4000    1.0 

(3)按照部门统计小于等于当前工资的人数占部门总人数的比例

  1. SELECT 
  2.  name
  3.  dept_num as deptno, 
  4.  salary, 
  5.  cume_dist() OVER (PARTITION BY dept_num ORDER BY salary) as cume 
  6. FROM employee; 

结果输出:

  1. name    deptno  salary  cume 
  2. Wendy   1000    4000    0.4 
  3. Will    1000    4000    0.4 
  4. Michael 1000    5000    0.6 
  5. Lucy    1000    5500    0.8 
  6. Steven  1000    6400    1.0 
  7. Lily    1001    5000    0.3333333333333333 
  8. Jess    1001    6000    0.6666666666666666 
  9. Mike    1001    6400    1.0 
  10. Yun     1002    5500    0.3333333333333333 
  11. Wei     1002    7000    0.6666666666666666 
  12. Richard 1002    8000    1.0 

(4)按部门分组,统计每个部门员工的工资以及大于等于该员工工资的下一个员工的工资

  1. SELECT 
  2.  name
  3.  dept_num as deptno, 
  4.  salary, 
  5.  lead(salary,1) OVER (PARTITION BY dept_num ORDER BY salary) as lead 
  6. FROM employee; 

结果输出:

  1. name    deptno  salary  lead 
  2. Wendy   1000    4000    4000 
  3. Will    1000    4000    5000 
  4. Michael 1000    5000    5500 
  5. Lucy    1000    5500    6400 
  6. Steven  1000    6400    NULL 
  7. Lily    1001    5000    6000 
  8. Jess    1001    6000    6400 
  9. Mike    1001    6400    NULL 
  10. Yun     1002    5500    7000 
  11. Wei     1002    7000    8000 
  12. Richard 1002    8000    NULL 

(5)按部门分组,统计每个部门员工的工资以及小于等于该员工工资的上一个员工的工资

  1. SELECT 
  2.  name
  3.  dept_num as deptno, 
  4.  salary, 
  5.  lag(salary,1) OVER (PARTITION BY dept_num ORDER BY salary) as lead 
  6. FROM employee; 

结果输出:

  1. name    deptno  salary  lead 
  2. Wendy   1000    4000    NULL 
  3. Will    1000    4000    4000 
  4. Michael 1000    5000    4000 
  5. Lucy    1000    5500    5000 
  6. Steven  1000    6400    5500 
  7. Lily    1001    5000    NULL 
  8. Jess    1001    6000    5000 
  9. Mike    1001    6400    6000 
  10. Yun     1002    5500    NULL 
  11. Wei     1002    7000    5500 
  12. Richard 1002    8000    7000 

(6)按部门分组,统计每个部门员工工资以及该部门最低的员工工资

  1. SELECT 
  2.  name
  3.  dept_num as deptno, 
  4.  salary, 
  5.  first_value(salary) OVER (PARTITION BY dept_num ORDER BY salary) as fval 
  6. FROM employee; 

结果输出:

  1. name    deptno  salary  fval 
  2. Wendy   1000    4000    4000 
  3. Will    1000    4000    4000 
  4. Michael 1000    5000    4000 
  5. Lucy    1000    5500    4000 
  6. Steven  1000    6400    4000 
  7. Lily    1001    5000    5000 
  8. Jess    1001    6000    5000 
  9. Mike    1001    6400    5000 
  10. Yun     1002    5500    5500 
  11. Wei     1002    7000    5500 
  12. Richard 1002    8000    5500 

(7)按部门分组,统计每个部门员工工资以及该部门最高的员工工资

  1. SELECT 
  2.  name
  3.  dept_num as deptno, 
  4.  salary, 
  5.  last_value(salary) OVER (PARTITION BY dept_num ORDER BY salary RANGE 
  6. BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as lval 
  7. FROM employee; 

结果输出:

  1. name    deptno  salary  lval 
  2. Wendy   1000    4000    6400 
  3. Will    1000    4000    6400 
  4. Michael 1000    5000    6400 
  5. Lucy    1000    5500    6400 
  6. Steven  1000    6400    6400 
  7. Lily    1001    5000    6400 
  8. Jess    1001    6000    6400 
  9. Mike    1001    6400    6400 
  10. Yun     1002    5500    8000 
  11. Wei     1002    7000    8000 
  12. Richard 1002    8000    8000 

注意:last_value默认的窗口是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,表示当前行永远是最后一个值,需改成RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。

img

  • RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

为默认值,即当指定了ORDER BY从句,而省略了window从句 ,表示从开始到当前行。

  • RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING

表示从当前行到最后一行

  • RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

表示所有行

  • n PRECEDING m FOLLOWING

表示窗口的范围是:[(当前行的行数)- n, (当前行的行数)+m]

 

责任编辑:武晓燕 来源: 大数据技术与数仓
相关推荐

2021-09-08 08:55:45

Javascript 高阶函数前端

2023-11-28 09:19:12

2022-01-04 06:50:12

数据摘要方法

2022-03-17 08:34:47

TypeScript项目类型

2022-03-30 09:01:37

CSS属性函数

2022-11-30 08:19:15

内存分配Go逃逸分析

2022-02-07 21:49:19

串行通信UART

2021-03-02 21:52:48

Hive数据类型

2022-09-28 11:34:27

用户行为数据业务

2020-03-31 09:09:48

Web安全网络攻击DDOS

2022-10-24 00:03:26

GolangNew函数

2022-10-17 08:22:28

2020-07-24 10:31:34

未授权访问漏洞

2022-07-07 08:01:51

Python魔法方法代码

2021-09-08 06:51:53

CountDownLa闭锁源码

2022-03-28 07:43:28

jsonHive数据库

2021-06-05 23:39:52

c++函数场景

2021-04-16 07:19:04

Hive数据类型Hql

2022-08-24 14:14:58

JavaScript函数

2022-08-02 11:29:17

数据分析场景RFM
点赞
收藏

51CTO技术栈公众号