hive窗口分析函数使用详解系列二之分组排序窗口函数
1.综述
我们讨论面试中各大厂的SQL算法面试题,往往核心考点就在于窗口函数,所以掌握好了窗口函数,面对SQL算法面试往往事半功倍。
已更新第一类聚合函数类,点击这里阅读 hive窗口函数聚合函数类
本节介绍Hive聚合函数中的第二类聚合函数:分组排序窗口函数。
这些函数的用法不仅仅适用于Hive,对于很多数数据库来说同样也适用,比如SparkSQL,FlinkSQL以及Mysql8,Oracle,MSSQL等传统的关系型数据库。
如果论使用的广泛性,hive窗口函数中我们使用最广泛的就是排序类窗口函数,我们通常一提起窗口函数,想到的就是这类排序类窗口函数,它在我们进行数据去重中扮演了至关重要的角色。
1.1 Hive窗口函数分类
Hive提供的窗口函数可以分为一下几类
- 聚合函数类
count() over();
sum() over();
max() over();
min() over();
avg() over();
- 分组排序类
row_number() over();
rank() over();
dense_rank() over();
percent_rank() over();
cume_dist() over();
ntile() over();
- 求偏移量类
lead() over();
lag() over();
first_value() over();
1.2 分析函数语法
分析函数 over(partition by 列名 order by 列名 rows between 开始位置 and 结束位置)
具体解析
over()
括号内为空时,是直接进行计算。
其中partition by 列名
是按指定列进行分组,进而进行计算。
最后的order by 列名
是按照指定列进行排序,进而进行计算。
1.3 基础数据准备
create table if not exists temp.user_info (
`id` bigint comment '用户id',
`client` string comment '客户端',
`gender` int comment '性别,0女1男',
`constellation` string comment '星座',
`age` int comment '年龄',
`pv` bigint comment '访问量',
`chat_num` bigint comment '聊天次数'
) comment '用户信息测试临时表'
数据预览
id | client | gender | constellation | age | pv | chat_num |
---|---|---|---|---|---|---|
1 | ios | 0 | 处女座 | 29 | 174 | 3 |
2 | ios | 1 | 双鱼座 | 26 | 263 | 2 |
3 | android | 1 | 双鱼座 | 35 | 232 | 39 |
4 | ios | 1 | 水瓶座 | 32 | 57 | 3 |
5 | ios | 1 | 射手座 | 33 | 67 | 6 |
6 | ios | 1 | 双子座 | 36 | 81 | 5 |
7 | ios | 1 | 狮子座 | 29 | 68 | 4 |
8 | ios | 1 | 狮子座 | 28 | 19 | 3 |
9 | ios | 0 | 射手座 | 32 | 479 | 2 |
10 | ios | 1 | 白羊座 | 26 | 255 | 36 |
2.各分组排序类函数的使用
2.1 row_number
- 功能
按照排序的顺序输出窗口中的数据的行号信息,不会出现排名相同的情况,且排名是连续的。即使是值相同,排名也会按照其排序顺序递增。
- 示例
按照星座分组,统计出pv由高到低的排名。
select id,client,gender,row_number() over(partition by constellation order by pv desc) as rank_id
from temp.user_info where id <= 10
数据结果:
id | client | gender | constellation | pv | rank_id |
---|---|---|---|---|---|
6 | ios | 1 | 双子座 | 81 | 1 |
2 | ios | 1 | 双鱼座 | 263 | 1 |
3 | android | 1 | 双鱼座 | 232 | 2 |
1 | ios | 0 | 处女座 | 174 | 1 |
9 | ios | 0 | 射手座 | 479 | 1 |
5 | ios | 1 | 射手座 | 67 | 2 |
4 | ios | 1 | 水瓶座 | 57 | 1 |
7 | ios | 1 | 狮子座 | 68 | 1 |
8 | ios | 1 | 狮子座 | 19 | 2 |
10 | ios | 1 | 白羊座 | 255 | 1 |
可以很清晰的看到按星座分组,每个星座内部的PV排名的id。例如,射手座用户id9排名第一,用户id5排名第二。
- 拓展使用:
更深一步的需求是筛出每个星座最高pv的用户,(或者说按星座去重,只取最高访问pv的用户)
再更进一步还可以计算诸如最大在线天数等SQL问题。
业务中常用用法为通过指定主键进行数据去重。
2.2 rank
- 功能
按照指定列进行排名,如果值相同,则排名并列,下一个排名会出现跳跃,即排名是不连续的。例如有前2个值一样,那么前2行并列第一,第3行的排名则为3。
- 示例
按使用客户端分组,统计年龄由高到低的排名。
select id,client,age,rank() over(partition by client order by age desc) as rank_id
from temp.user_info where id <= 10
数据结果:
id | client | age | rank_id |
---|---|---|---|
3 | android | 35 | 1 |
6 | ios | 36 | 1 |
5 | ios | 33 | 2 |
9 | ios | 32 | 3 |
4 | ios | 32 | 3 |
1 | ios | 29 | 5 |
7 | ios | 29 | 5 |
8 | ios | 28 | 7 |
2 | ios | 26 | 8 |
10 | ios | 26 | 8 |
可以看到上述信息中,通过安卓和iOS客户端的年龄大小排名。其中32岁两个并列第三,没有第四名,直接开始第五名。相同值进行并列。rank_id的排名是不连续的。
- 拓展使用:
常用于指定排名场景。
2.3 dense_rank
- 功能
该函数可以和rank()
对照使用,按照指定列排序的顺序输出窗口中的数据的排名,如果值相同时,排名并列,下一个排名是连续递增的,不会出现跳跃情况。即如果前2行的值相同,则前2行并列第1,第3行的排名则为第2。
可以理解为一个为疏松排名(rank),一个为密集排名(dense_rank)
- 示例
按使用客户端分组,统计年龄由高到低的排名。
select id,client,age,dense_rank() over(partition by client order by age desc) as rank_id
from temp.user_info where id <= 10
数据结果:对比上文
id | client | age | rank_id |
---|---|---|---|
3 | android | 35 | 1 |
6 | ios | 36 | 1 |
5 | ios | 33 | 2 |
9 | ios | 32 | 3 |
4 | ios | 32 | 3 |
1 | ios | 29 | 4 |
7 | ios | 29 | 4 |
8 | ios | 28 | 5 |
2 | ios | 26 | 6 |
10 | ios | 26 | 6 |
可以看到,排名没有出现跳跃,是连续的,相同排名并列其名次。例如ios的32岁两个并列第三老。
- 拓展使用
和rank相反,我希望出现不中断的排名,这样的使用场景。
2.4 percent_rank
- 功能
见名知意,按百分比进行排名。
与 percent 函数类似,percent_rank (分布函数)函数的窗口 order by 子句所指定列中的值的返回值,是介于 0 和 1 之间的小数形式表示。
- 计算方法
(rank - 1) / (n - 1)
rank为上述rank()
函数的排名,n 为当前窗口的总数。
- 示例
按使用客户端分组,统计年龄由高到低的百分比排名(percent_rank)。
另一种问法:某某用户的年龄(或者其他指标)在ios客户端排名前百分之多少?
select id,client,age,percent_rank() over(partition by client order by age desc) as rank_id
from temp.user_info where id <= 10
数据结果:
id | client | age | rank_id |
---|---|---|---|
3 | android | 35 | 0.0 |
6 | ios | 36 | 0.0 |
5 | ios | 33 | 0.125 |
9 | ios | 32 | 0.25 |
4 | ios | 32 | 0.25 |
1 | ios | 29 | 0.5 |
7 | ios | 29 | 0.5 |
8 | ios | 28 | 0.75 |
2 | ios | 26 | 0.875 |
10 | ios | 26 | 0.875 |
可以看出,用户9和4的年龄32岁排名ios客户端前百分之二十五,其并列排名。
- 拓展使用
该函数经常用于较大数据量的百分比占比分析,也常用于探究数据分布分析场景。
例如可以通过分布函数踢除极值,进而求解均值,降低数据误差。
2.5 cume_dist
- 功能
如果按升序排列,则统计:小于等于当前值的行数所占当前分区窗口总行数的比例。(number of rows ≤ current row)/(total number of rows)。
如果是降序排列,则统计:大于等于当前值的行数所占当前分区窗口总行数的比例。
- 示例
1.统计小于等于当前年龄的人数占总人数的比例。
另一种问法:小于等于29岁的人占总人数的比例。
select id,client,age,cume_dist() over(order by age desc) as rank_id
from temp.user_info where id <= 10
order by age
数据结果:
id | client | age | rank_id |
---|---|---|---|
2 | ios | 26 | 0.2 |
10 | ios | 26 | 0.2 |
8 | ios | 28 | 0.3 |
1 | ios | 29 | 0.5 |
7 | ios | 29 | 0.5 |
4 | ios | 32 | 0.7 |
9 | ios | 32 | 0.7 |
5 | ios | 33 | 0.8 |
3 | android | 35 | 0.9 |
6 | ios | 36 | 1.0 |
可以看到小于等于29岁所占人群的总比例为50%。
2.统计当前客户端分区小于等于当前年龄的人数占总人数的比例。
另一种问法:ios客户端小于等于29岁的人占总人数的比例。
select id,client,age,cume_dist() over(partition by client order by age) as rank_id
from temp.user_info where id <= 10
order by age
数据结果:
id | client | age | rank_id |
---|---|---|---|
2 | ios | 26 | 0.2222222222222222 |
10 | ios | 26 | 0.2222222222222222 |
8 | ios | 28 | 0.3333333333333333 |
1 | ios | 29 | 0.5555555555555556 |
7 | ios | 29 | 0.5555555555555556 |
4 | ios | 32 | 0.7777777777777778 |
9 | ios | 32 | 0.7777777777777778 |
5 | ios | 33 | 0.8888888888888888 |
3 | android | 35 | 1.0 |
6 | ios | 36 | 1.0 |
可以看到ios客户端小于等于29岁的人群占比为55.6%左右。
- 拓展使用
该函数是一个累积求比例的函数,常用于求解排名前百分之多少或者排名后百分之多少的问题。
2.6 ntile
- 功能
分桶窗口函数,用于将按指定列分组的数据按照顺序切分成N片,返回当前切片值。将一个有序的数据集划分为多个桶(bucket),并为每行分配一个适当的桶数(切片值,第几个切片,第几个分区等概念)。它可用于将数据划分为相等的小切片,为每一行分配该小切片的数字序号。
- 注意
ntile不支持rows between,range between.
- 示例
统计按照客户端分组,按年龄排序,将每个窗口分成3片(桶),返回每片(桶)的的分片(桶)信息。
另一种问法:把ios客户端的人群按年龄正序分成三部分,返回任意一部分的值。
select id,client,age,cume_dist() over(partition by client order by age) as rank_id
from temp.user_info where id <= 10
order by age
数据结果:
id | client | age | rank_id |
---|---|---|---|
3 | android | 35 | 1 |
10 | ios | 26 | 1 |
2 | ios | 26 | 1 |
8 | ios | 28 | 1 |
7 | ios | 29 | 2 |
1 | ios | 29 | 2 |
4 | ios | 32 | 2 |
9 | ios | 32 | 3 |
5 | ios | 33 | 3 |
6 | ios | 36 | 3 |
可以看到ios客户端9人被分为三部分,需要哪一部分,只要再限制rank_id 等于几就行。
- 拓展使用
该函数是一个分桶函数,可以按照指定的列把数据均匀的分成想要的几部分数据。
例如,求解用户活跃时长前百分之二十的群体,如果包含0活跃时长用户,用百分比排序就不好计算了,而用该函数可以很快计算出来。
以上,为本次分享内容。
后续计划会开启一个新的系列内容:SQL每日一题系列,多来自各大厂的高频面试题,有好的算法面试题也可以积极分享,互相交流。
感谢阅读。
下一期:hive窗口分析函数使用详解之三-求偏移量类窗口函数
按例,欢迎点击此处关注我的个人公众号,交流更多知识。
hive窗口分析函数使用详解系列二之分组排序窗口函数的更多相关文章
- Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能
Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...
- Eureka详解系列(二)--如何使用Eureka(原生API,无Spring)
简介 通过上一篇博客 Eureka详解系列(一)--先谈谈负载均衡器 ,我们知道了 Eureka 是什么以及为什么要使用它,今天,我们开始研究如何使用 Eureka. 在此之前,先说明一点.网上几乎所 ...
- GridControl详解(四)分组排序汇总
分组: 按时间分第一组: 按性别分第二组: 显示结果: 高级设置: 将所有组展开代码:gridView1.ExpandAllGroups(); 显示结果: 自定义组名,GridView级事件 增加事件 ...
- Java源码详解系列(十二)--Eureka的使用和源码
eureka 是由 Netflix 团队开发的针对中间层服务的负载均衡器,在微服务项目中被广泛使用.相比 SLB.ALB 等负载均衡器,eureka 的服务注册是无状态的,扩展起来非常方便. 在这个系 ...
- Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节
简介 这是 Mybatis 系列博客的第四篇,我本来打算详细讲解 mybatis 的配置.映射器.动态 sql 等,但Mybatis官方中文文档对这部分内容的介绍已经足够详细了,有需要的可以直接参考. ...
- Java源码详解系列(十)--全面分析mybatis的使用、源码和代码生成器(总计5篇博客)
简介 Mybatis 是一个持久层框架,它对 JDBC 进行了高级封装,使我们的代码中不会出现任何的 JDBC 代码,另外,它还通过 xml 或注解的方式将 sql 从 DAO/Repository ...
- Eureka详解系列(四)--Eureka Client部分的源码和配置
简介 按照原定的计划,我将分三个部分来分析 Eureka 的源码: Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系): Eureka Client ...
- Eureka详解系列(五)--Eureka Server部分的源码和配置
简介 按照原定的计划,我将分三个部分来分析 Eureka 的源码: Eureka 的配置体系(已经写完,见Eureka详解系列(三)--探索Eureka强大的配置体系): Eureka Client ...
- 干货 | BitSail Connector 开发详解系列一:Source
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 BitSail 是字节跳动自研的数据集成产品,支持多种异构数据源间的数据同步,并提供离线.实时.全量.增量场景下全 ...
- 大数据学习系列之五 ----- Hive整合HBase图文详解
引言 在上一篇 大数据学习系列之四 ----- Hadoop+Hive环境搭建图文详解(单机) 和之前的大数据学习系列之二 ----- HBase环境搭建(单机) 中成功搭建了Hive和HBase的环 ...
随机推荐
- Java 抽象类的应用:模板方法的设计模式
1 package com.bytezreo.template; 2 3 /** 4 * 5 * @Description 抽象类的应用:模板方法的设计模式 6 * @author Bytezero· ...
- Codeforces Round 345 (Div. 1)A. Watchmen(容斥原理)
A. Watchmen 当欧几里得距离和曼哈顿距离相等时,\(x1==x2||y1==y2\) 这两个条件满足其一.这和容斥原理一样,至少选择一个的条件. 我们可以计算xi,以及小于i之前的这些,这样 ...
- 本地画板工具 Axure RP 9 顶替 drawio (补充Axure RP 8)
本地画板工具 Axure RP 9 顶替 drawio 外链:https://wws.lanzoul.com/b03paemkf 密码:dmvj 9这个版本 win7 不支持 Axure RP 8 h ...
- vue 动态加载css,改变网站皮肤模式
Vue.mixin({ created () { require('view-design/dist/styles/iview.css') } }) 参考资料:https://blog.csdn.ne ...
- pod的拉取和重启策略
在Kubernetes中,Pod的拉取策略和重启策略可以通过YAML配置文件来定义. Pod的拉取策略 Pod的拉取策略指的是Kubernetes在创建或重启Pod时,如何获取Pod所需的容器镜像.这 ...
- 自我总结的git的使用
git是什么 git是一个分布式版本控制工具,github是代码托管平台. git有什么用 保存文件的所有修改记录 使用版本号进行区分 随时可浏览历史版本记录 可还原到历史指定版本 对比不同版本的文件 ...
- 工作中最常见的6种OOM问题
前言 最近我写的几篇线上问题相关的文章:<糟糕,CPU100%了><如何防止被恶意刷接口><我调用第三方接口遇到的13大坑>发表之后,在全网广受好评. 今天接着线上 ...
- linux介绍、安装、shell
1-Linux发展介绍 零 什么是Linux Linux:和我们常见的Windows一样,都是操作系统,但不同的是: Windows: 收费,不开源,主要用于日常办公.游戏.娱乐多一些. Linux: ...
- Liunx-LVM创建与扩容
LVM是 Logical Volume Manager(逻辑卷管理)的简写,它是Linux环境下对磁盘分区进行管理的一种机制,它由Heinz Mauelshagen在Linux 2.4内核上实现,最新 ...
- 替代 Redis 的开源项目「GitHub 热点速览」
近日,知名开源项目 Redis 宣布修改开源协议,从原来的「BSD 3-Clause 开源协议」改成「RSALv2 和 SSPLv1 双重许可证」.新的许可证主要是限制托管 Redis 产品的云服务商 ...