HIVE--hive的窗口函数(开窗函数,分析函数)

简介

sql中有一类函数叫做聚合函数,例如sum()、avg()、max()等等,这类函数可以将多行数据按照规则聚集为一行,一般来讲聚集后的行数是要少于聚集前的行数的.但是有时我们想要既显示聚集前的数据,又要显示聚集后的数据,这时我们便引入了窗口函数.

开窗函数

开窗函数一般就是说的是over()函数,其窗口是由一个 OVER 子句 定义的多行记录,其作用就如同它的名字,就是限定出一个窗口。

分析函数

分析函数种类较多,指的是对数据进行各种处理,分析的函数,大体上包括但不仅限于:聚合函数,排名函数,取一些特定位置范围的数值的函数等等。

分析函数和聚合函数的关系

聚合函数的作用域是由 GROUP BY 子句聚合的组,而窗口函数则作用于一个窗口,。聚合函数对其所作用的每一组记录输 出一条结果,而窗口函数对其所作用的窗口中的每一行记录输出一条结果,简单理解,就是对查询的结果多出一列,这一列可以是聚合值,也可以是排序值。

开窗函数与分析函数的关系

开窗函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化
可以理解为一个分析函数必然要搭配一个窗口函数,以指定原数据的规则,便于分析函数实现。

注意

有很多文档或资料中,对以上函数的叫法较为混乱,现做以下整理(不断补充):

窗口函数:一般指的是分析函数,有时指的是开窗+分析
聚合开窗函数,排序开窗函数:指的是开窗+分析,是安装分析函数的不同类型进行的命名。聚合开窗函数指的分析函数类型是聚合函数,排序开窗函数指的分析函数是排序函数。

开窗函数

over()开窗函数,其括号内部主要有两种形式,固定搭配,不能更改:
over(distribute by…sort by…) 和 over(partition by…order by…)

两种开窗方式区别

patition by是按照一个一个reduce去处理数据的,所以要使用全局排序order by
distribute by是按照多个reduce去处理数据的,所以对应的排序是局部排序sort by

开窗函数的窗口大小问题

窗口大小:hive的窗口大小默认是从起始行到当前行的

典型问题

select dt,name,score,
min(score) 
over(distribute by dt sort by score desc)
from student;

注意点:此处的min()函数是分析函数,而不是聚合函数,所以其作用范围是由开窗函数over()限定的。
结果为:
在这里插入图片描述
此时最后一列最小分数的结果是有问题的,问题根源就在于窗口大小的变化,由默认的窗口大小规则可知,此处的排序规则应定为升序排序。

窗口大小的设置(也叫window子句)

  • 默认窗口大小是从起始行到当前行
  • partition by …order by…rows between unbounded preceding and current row
    窗口大小为从起始行得到当前行。
  • partition by …order by… rows between 3 preceding and current row
    窗口大小为从当前行到之前三行
  • partition by …order by… rows between 3 preceding and 1 following
    窗口大小为当前行的前三行到之后的一行
  • partition by …order by… rows between 3 preceding and unbounded following
    窗口大小为当前行的前三行到之后的所有行

分析函数

注意(重要,决定了窗口函数的使用场景问题):

1 分析函数的使用一定要注意窗口的范围,因为窗口的范围限定了分析函数的作用范围
2 分析函数会对窗口中的每一行数据输出一个结果,即会对查询的结果多出一列,这一列可以是聚合结果,也可以是排序结果

sum() avg() max() min()

和原来的聚合函数是一样的效果。
书写顺序: sum( ) over( )

排名函数

注意:排名函数不支持window子句,即不支持自定义窗口大小

row_number(): 没有并列,相同名次顺序排序

rank(): 有并列,相同名次空位(即类似于1 1 3)

dense_rank(): 有并列,相同名次不空位(即类似于1 1 2)

注意:窗口函数的别名位置是在over()子句之后

lag() lead() first_value() last_value()

lag()
LAG(col,n,DEFAULT) 用于统计窗口内往上第n行值
第一个参数为列名,第二个参数为往上第n行(可选,默认为1),第三个参数为默认值(当往上n行之内,若当某一行为NULL时候,取默认值,如不指定,则为NULL)

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

first_value()
取分组内排序后,截止到当前行,第一个值.
如果不指定ORDER BY,则默认按照记录在文件中的偏移量进行排序,会出现错误的结果

last_value()
取分组内排序后,截止到当前行,最后一个值
如果不指定ORDER BY,则默认按照记录在文件中的偏移量进行排序,会出现错误的结果

注意事项,易错点

当在查询过程中,在嵌套子查询中使用了窗口函数以后,那么在嵌套子查询外,一定要使用上窗口字段,否则,最后的结果是和使用过窗口函数那个表是毫无关系的。

举例:

//环境是spark环境,但是原理一样
val df2: DataFrame = scc.sql("select id,time,url from  (" +
      "select *,dense_rank() over(distribute by id sort by unix_timestamp(time,'HH:mm:ss') asc) rk1 " +
      "from URL) where rk1<>0")
/**
此处,本身我不需要排序字段,只要排序后,将其他字段拿出即可,但是如果不加rk1字段,是跟原来一模一样,和没使用开窗函数是一样的。
所以,我最后为了最后结果,要在where上加上rk1字段,而且,跟嵌套子查询嵌了几层没关系,只要使用了,然后嵌套外层又没使用窗口结果字段,那么就不行
*/
  • 13
    点赞
  • 137
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值