窗口函数在工作中经常用到,在面试中也会经常被问到,你知道它背后的实现原理吗?

这篇文章从一次业务中遇到的问题出发,深入聊了聊hsql中窗口函数的数据流转原理,在文章最后针对这个问题给出解决方案。

一、业务背景

先模拟一个业务背景,比如大家在看淘宝app时,如下图:

搜索一个关键词后,会给展示一系列商品,这些商品有不同的类型,比如第一个是广告商品,后面这几个算是正常的商品。把这些数据用下面的测试表来描述:

create 

在该表中插入以下数据:

以上数据中,cell_type列,假设26代表是广告,现在有个需求,想获取每个用户每次搜索下非广告类型的商品位置自然排序,如果下效果:

业务方的实现方法:

--业务方的写法

结果如下:

上面这种写法的结果显然不是我们想要的,虽然把26类型的rank去掉,但是非广告类的商品的位置排序没有向上补充

为什么呢?感觉写的也没错呀?~~~~

下面,我们来盘一盘window Funtion的实现原理

二、window 实现原理

在分析原理之前,先简单过一下window Funtion的使用范式:

select

上面的语句主要分两部分

  1. window函数部分(window_func)
  2. 窗口定义部分

2.1 window函数部分

windows函数部分就是所要在窗口上执行的函数,spark支持三中类型的窗口函数:

  1. 聚合函数 (aggregate functions)
  2. 排序函数(Ranking functions)
  3. 分析窗口函数(Analytic functions)

第一种都比较熟悉就是常用的count 、sum、avg等

第二种就是row_number、rank这样的排序函数

第三种专门为窗口而生的函数比如:cume_dist函数计算当前值在窗口中的百分位数

2.2 窗口定义部分

这部分就是over里面的内容了里面也有三部分

  1. partition by
  2. order by
  3. ROWS | RANGE BETWEEN

前两部分就是把数据分桶然后桶内排序,排好了序才能很好的定位出你需要向前或者向后取哪些数据来参与计算。这第三部分就是确定你需要哪些数据了。

spark提供了两种方式一种是ROWS BETWEEN也就是按照距离来取例如

  1. ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW就是取从最开始到当前这一条数据,row_number()这个函数就是这样取的
  2. ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING代表取前面两条和后面两条数据参与计算,比如计算前后五天内的移动平均就可以这样算.

还有一种方式是RANGE BETWEEN 这种就是以当前值为锚点进行计算。比如RANGE BETWEEN 20 PRECEDING AND 10 FOLLOWING当前值为50的话就去前后的值在30到60之间的数据。

2.3 window Function 实现原理

窗口函数的实现,主要借助 Partitioned Table Function (即PTF);

PTF的输入可以是:表、子查询或另一个PTF函数输出;

PTF输出也是一张表。

写一个相对复杂的sql,来看一下执行窗口函数时,数据的流转情况:

select 

数据流转如下图:

以上代码实现主要有三个阶段:

  • 计算除窗口函数以外所有的其他运算,如:group by,join ,having等。上面的代码的第一阶段即为:
select

  • 将第一步的输出作为第一个 PTF 的输入,计算对应的窗口函数值。上面代码的第二阶段即为:
select 

由于row_number(),rank() 两个函数对应的窗口是相同的(partition by id order by rank),因此,这两个函数可以在一次shuffle中完成。

  • 将第二步的输出作为 第二个PTF 的输入,计算对应的窗口函数值。上面代码的第三阶段即为:
select 

由于dense_rank()的窗口与前两个函数不同,因此需要再partition一次,得到最终的输出结果。

以上可知,得到最终结果,需要shuffle三次,反应在 mapreduce上面,就是要经历三次map->reduce组合;反应在spark sql上,就是要Exchange三次,再加上中间排序操作,在数据量很大的情况下,效率基本没救~~

这些可能就是窗口函数运行效率慢的原因之一了。

这里给附上spark sql的执行计划,可以仔细品一下(hive sql的执行计划实在太长,但套路基本是一样的):

spark

三、解决方案

回顾上面sql的写法:

select 

从执行计划中,可以看到sql中 if 函数的执行位置如下:

spark

数据流转:

if函数在partition以及row_number后执行,因此得到的位置排名不正确。

改写一下:

select 

这样写法要注意的地方:要保证 rand() 函数不会与id发生碰撞。

或者下面的写法也可以:

select 

缺点就是要读两遍 window_test_table 表

http://weixin.qq.com/r/pi06IojEMtVNrcxB93i0 (二维码自动识别)

推荐阅读:

flink_sql_client 1.10 与 hive集成 读取实时数据​mp.weixin.qq.com

Flink_sql_client1.10源码在IDEA中集成hive并运行​mp.weixin.qq.com

有关用户留存模型的一种设计方法​mp.weixin.qq.com

spark sql多维分析优化——细节是魔鬼​mp.weixin.qq.com

记录一次spark sql的优化过程​mp.weixin.qq.com

从一个sql引发的hive谓词下推的全面复盘及源码分析(上)​mp.weixin.qq.com

从一个sql引发的hive谓词下推的全面复盘及源码分析(下)​mp.weixin.qq.com

hive 修改cluster by算法_spark、hive中窗口函数实现原理复盘相关推荐

  1. hive 修改cluster by算法_Hive入门实战(一)概述与使用

    一.Hive基本概念 1.概念 Hive:由Facebook开源用于解决海量结构化日志的数据统计. Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询 ...

  2. hive 修改cluster by算法_疯狂Hive之DML操作(四)

    DML操作 Load 在将数据加载到表中时,Hive不会进行任何转换.加载操作是将数据文件移动到与Hive表对应的位置的纯复制.移动操作. 语法结构: load data [local] inpath ...

  3. hive 修改cluster by算法_Hive基础之导出数据

    我们在hive中分析完数据后有时候需要将结果导出到本地文件以供其他用途.hive中提供了几种方式来导出结果,下面就详细介绍一些这几种导出数据的方法. 1.导出到本地文件目录 (default 查看一下 ...

  4. hive 修改cluster by算法_双重聚类cluster咋做? 线性, logit, tobit可以双聚类吗?

    凡是搞计量经济的,都关注这个号了 邮箱:econometrics666@sina.cn 所有计量经济圈方法论丛的code程序, 宏微观数据库和各种软件都放在社群里.欢迎到计量经济圈社群交流访问. 上一 ...

  5. 超全面试汇总——Hive 超详细!!!带答案!!!持续更新中~

    Hive面试总结 什么是 Hive ? Hive结构描述 Hive的优势 内部表.外部表.分区表.分桶表 hive中 排序的种类和适用场景 动态分区和静态分区的区别 + 使用场景 hive 语句执行顺 ...

  6. hive 临时表 with_Kettle(PDI)转换中输入表输入详解

    概述 Table input(表输入)此步骤使用SQL语句从连接的数据库中读取信息.通过单击获取SQL查询语句按钮,可以自动生成基本SQL语句. 选项 Table input(表输入)步骤有以下选项: ...

  7. HIVE的安装配置、mysql的安装、hive创建表、创建分区、修改表等内容、hive beeline使用、HIVE的四种数据导入方式、使用Java代码执行hive的sql命令

    1.上传tar包 这里我上传的是apache-hive-1.2.1-bin.tar.gz 2.解压 mkdir -p /home/tuzq/software/hive/ tar -zxvf apach ...

  8. Hive 区分cluster by、distribute by + sort by、order by以及创建表带有clustered by和sort by

    Hive 区分cluster by.distribute by + sort by.order by以及创建表带有clustered by和sort by 本文主要根据一些具体SQL实例来介绍说明cl ...

  9. hive同时不包含一些字符串_Hive中常用的字符串操作

    一.准备 创建虚表: echo "X" >> dual.tsv hadoop fs -put dual.tsv '/data//' create table dual( ...

最新文章

  1. 历史 history
  2. python celery
  3. http headers详解
  4. Tensorflow Day18 Convolutional Autoencoder
  5. kafka整理笔记笔记
  6. shell 删除七日内日志_shell日志删除(超容量自动)
  7. 转载大神的一篇文章----【如何选择开源许可证?】
  8. 为何加入了AddType就无法启动Apache
  9. 【微信商城小程序怎么弄】微信商城小程序开发的基本流程
  10. 几种简单电路知识汇总
  11. 女生做软件测试的利弊如何权衡?
  12. Windows XP 注册表修改大全
  13. 希尔顿集团大中华区第450家酒店开业;Gap在山东青岛开新店 | 美通企业日报
  14. 读懂SIEM建设?看这篇就够了!
  15. PDF转成Word或PPT后不能修改的原因和解决方法
  16. 我的CSDN博客规划说明
  17. 万字长文,Java接地气日常编码技巧
  18. 数据中心服务器机柜电气参数,数据中心服务器机柜一些安装与参数
  19. 学习canvas(一):用线画出正方形和三角形
  20. 计算机视觉标定方法,计算机视觉测量中摄像机快速标定方法实现

热门文章

  1. kite:Python 代码自动补全神器
  2. [再学Python] - 2 - math库和random库
  3. RabbitMQ用户角色及权限控制
  4. Kong API Gateway 配置文件详解
  5. 安卓运行时监听配置更改:sim卡、本地语言、键盘显示或隐藏、字体大小、UI模式、屏幕方向、屏幕布局(另一个屏幕)、可用屏幕大小(横纵向)、无屏幕大小(外接屏幕)。
  6. docker从C盘迁移到E盘
  7. 贺利坚老师汇编课程47笔记:jmp指令无条件转移只修改IP
  8. oracle sga设置 256G,Oracle SGA大小的解决方法的调整
  9. spring mvc-基础-简单程序
  10. AngularJS------报错The selector app-user-item did not match any elements