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.block; 2 3 /** 4 * 5 * @Description 类的成员之四: 代码块(或初始化块) 6 * @author Bytezero·z ...
- 机器学习从入门到放弃:卷积神经网络CNN(二)
一.前言 通过上一篇文章,我们大概了解了卷积是什么,并且分析了为什么卷积能在图像识别上起到巨大的作用.接下来,废话不多话,我们自己尝试动手搭建一个简易的CNN网络. 二.准备工作 在开始的时候,我们首 ...
- XAF Number(编号)
前言 编号在各类系统中都会存在,同时它还会根据业务场景的不同,会有不同的生成规则.XAF提供了一个编号生成助手(DistributedIdGeneratorHelper),它能在多并发的情况下,生成一 ...
- iview 多弹框,显示z-index 不对,被遮挡的解决方案 goTop函数 modal Drawer 抽屉
iview 多弹框,显示z-index 不对,被遮挡的解决方案 goTop函数 modal 原因 弹多个modal框的时候,会被遮挡,导致后显示的框在下面 解决原理 获取当前弹框的z-index,然后 ...
- 关于hashCode和equals重写
规则 只要重写equals,就必须重写hashCode. 用Set存储对象或者用对象作为Map的键时,必须重写hashCode.也就是说,当需要用对象的哈希值来判断对象是否相等时必须重写hashCod ...
- Linux 服务器Python后台运行服务(ssh断开不退出)
壹: 最近用python搭建一个物联网数据存储的微服务,部署到ubuntu上去,所以,python后台运行是一个必不可少的环节. 贰: 这个只需要是一个命令即可: 命令1(记录所有日志): nohup ...
- 基于ADS1292芯片的解决方案之芯片简析
基本资料: ADS1292芯片是多通道同步采样 24 位 Δ-Σ 模数转换器 (ADC),它们具有内置的可编程增益放大器 (PGA).内部基准和板载振荡器. ADS1292 包含 便携式 低功耗医疗心 ...
- Handler源码解析
Handler源码解析 一.基本原理回顾 在android开发中,经常会在子线程中进行一些操作,当操作完毕后会通过handler发送一些数据给主线程,通知主线程做相应的操作. 探索其背后的原理:子线程 ...
- 23_FFmpeg像素格式转换
简介 前面使用 SDL 显示了一张YUV图片以及YUV视频.接下来使用Qt中的QImage来实现一个简单的 YUV 播放器,查看QImage支持的像素格式,你会发现QImage仅支持显示RGB像素格式 ...
- 记录--H5页面对接微信支付踩坑杂记
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 背景 应用背景:vite搭建的vue3项目 需求背景:功能都涉及了支付业务,故需要和外部支付系统对接 外部支付系统:聚合支付.微信小程序支 ...