简介: MaxCompute 挑战使用SQL进行序列数据处理 --而不是用MR和函数

日常编写数据加工任务,主要的方法就是使用SQL。第一是因为自己对SQL掌握的比较好(十多年数据开发经验,就这几个关键字,也不敢跟别人说自己不行),所以,MR和函数涉及不多。在接触MaxCompute这些年,写过的函数应该不超过10个,主要还是因为自己JAVA水平挫。记得早些年写过一个身份证号码校验函数,当时有个项目反馈一段SQL原来2分钟,使用我的函数就变成12分钟了。当时这个项目组还找到MaxCompute的研发,研发负责人又找到我,让我把我的代码调优下。我很惶恐啊,我是什么渣,我自己心里知道啊。最后还是厚着脸皮求研发帮我优化了下,性能终于改进了。这以后,我更不敢随机作函数了,毕竟MaxCompute官方建议尽可能使用SQL,SQL是优化过的方法,自己用MR和自定义函数性能是很难保障的。这也导致我至今在这方面也是渣渣,当然我认为错不在我,我只是听了“妈妈”的话而已。

最近很奇妙,接连有两个项目遇到了序列值计算的问题,还都是要求不能使用函数和MR。同事把问题送给我,我发现光读懂题都要半天(题目有点绕),不在一线搞开发太久了,有点生疏了。同样的问题,第一次搞了一天,第二次还搞了半天,没说很快能搞出来的,未免有点丢范。所以,总结出来跟大家分享下。

先说下什么是序列值的处理。表中的记录本身是无序的,但是业务上数据都是有序的,一般来说时间就是一个自然的序列。比如利用我一天的作息的时点记录,计算我一天吃了几次饭,吃了多久。乍一看,好像要写个函数。

问题模拟如下:

问题:吃了几次饭,都吃了多久?

条件:1-两个吃饭状态间隔在1小时内,算作一顿饭

2-最后一个吃饭状态后的下一个其他状态的开始时间,是吃饭的结束时间

通过上面的分析,我们可以得到结果:大约吃了四次饭,因为晚上吃饭的时间很长,按照规则算作吃了两次饭(第四次看起来是去撸串了)。我是怎么做的呢?第一步,我先把无关的信息剔除了,第1行、第4行、最后1行。第二步,后我利用数据是连续的时间的特质,找到了状态的结束时间。第三步,我识别了状态间隔1小时这个特征,识别出了一个“吃饭”中混杂的其他无关状态,并且还分析得到第三个“吃饭”和第四个“吃饭”状态是两个独立的状态。

那么用SQL怎么实现?排序是一定的了,要排序还要处理状态,必须使用窗口函数。能选的窗口函数似乎只有lag、lead。

窗口函数:

LAG  按偏移量取当前行之前第几行的值。

LEAD 按偏移量取当前行之后第几行的值。

官方文档:https://help.aliyun.com/document_detail/34994.html

即便有了这个函数,还有一个问题很头疼,函数需要指定偏移量,而这个问题里面并不知道到底会出现多少个状态。是不是也没有用呢?看看再说。

问题分解分解如下:

使用LAG\LEAD函数取到前一条记录和后一条记录的状态和时间,分析记录:

1-当前状态不是“吃饭”,上一个状态也不是“吃饭”,记录不保留。

2-当前状态不是“吃饭”,上一个状态是“吃饭”,为上一个状态提供结束时间,记录不保留。

3-当前状态是“吃饭”,记录上一个和下一个状态都是“吃饭”,记录不保留。

4-当前状态是“吃饭”,记录下一个状态时间,作为当前状态结束时间,记录保留。

如下图:

然后我们就得到了下面一个表格:

很明显,这不是我们最后需要的。虽然我们找到了状态为“吃饭”的行,并且通过窗口函数给它找到了状态的结束实际。但是表格还需要再作一次处理,才能变成我们想要的结果。再次使用LAG\LEAD函数,我们需要把间隔在1小时内的“吃饭”状态进行合并。

 

问题再次分解分解如下:

使用LAG\LEAD函数取到前一条记录和后一条记录的开始和结束时间,分析记录:

1-当前记录的“开始时间”减去上个时点的“结束时间”,如果小于1小时,该行记录不保留。这一行记录的状态需要与上一行合并为一次“吃饭”状态。下图中绿色标注行。

2-下个时点的“开始时间”减去当前记录的“结束时间”,如果小于1小时,该行记录与下一行记录合并。修改当前时点“吃饭”状态的结束时间为下一个时点的结束时间。下图橙色标注行。

然后我们得到了下面的表格:

不管之前我们想的多复杂,需要用什么循环或者递归逻辑实现,但是现在问题解决了。我们通过这个表格回答了最开始题目的问题。这个人吃过4次饭,开始时间分别是7点10分、12点25分、17点40分、19点45分,每次持续的时间大约都在1小时。这个过程就是一个找到需要的信息,剔除无关信息的过程,只不过这个where有点复杂。

其实从分析问题的角度来看,这个问题本身就有点复杂,搞懂问题一般都需要一定的时间。从实现问题的角度来看,使用高级语言JAVA或者python实现更容易点,循环撸一遍有什么解决不了的(一遍不够再来一遍)。用SQL实现,看起来有点复杂(可能是我常年使用SQL语言的原因,我觉得我好像分析问题的过程跟实现的过程是一样的。),但是代码量一定是最少的(性能可能也是最佳的)。再从可维护性上去综合比较,还是使用SQL实现更优。

所以,后面再遇到类似的问题,你应该可以搞定了。如果有点困难,至少你可以再回过头来看下这个例子,毕竟我花了好久来设计。

SQL问题解答:

with ta as(

select*

from values

(1001,'06:05:00','sleep')

,(1001,'07:10:00','eat')

,(1001,'08:15:00','phone')

,(1001,'11:20:00','phone')

,(1001,'12:25:00','eat')

,(1001,'12:40:00','phone')

,(1001,'13:30:00','eat')

,(1001,'13:35:00','sleep')

,(1001,'17:40:00','eat')

,(1001,'18:05:00','eat')

,(1001,'18:25:00','eat')

,(1001,'18:30:00','phone')

,(1001,'19:45:00','eat')

,(1001,'20:55:00','phone')

,(1001,'22:00:00','sleep')

t(id,stime,stat))

-- 5 计算根据前后记录的时间,判断记录是否要被合并

selectid,stime

,case whens2<=60 thenetime2 else etime end asetime,stat

from(

-- 4 计算前后记录的时间差

selectid,stime,etime,stat

,datediff(stime,etime1,'mi') ass1

,datediff(stime2,etime,'mi') ass2

,etime2

from(

-- 3 计算前后记录的时间

selectid,stime,etime,stat

,lag (stime,1) over(partition byid order by stime asc)as stime1

,lag (etime,1) over(partition byid order by stime asc)as etime1

,lead(stime,1) over(partition byid order by stime asc)as stime2

,lead(etime,1) over(partition byid order by stime asc)as etime2

from(

-- 2 识别前后记录状态,找到状态结束时间

selectid,stime,stat

,lead(stime,1) over(partition byid order by stime asc)as etime

,lag (stat,1) over(partition byid order by stime asc)as stat1

,lead(stat,1) over(partition byid order by stime asc)as stat2

from(

-- 1 把字符串转时间

selectid,to_date(concat('2021-06-29 ',stime),'yyyy-mm-dd hh:mi:ss') asstime,stat

fromta)t1)t2

wherestat='eat' and not(stat='eat' andstat1='eat' andstat2='eat'))t3)t4

wheres1 >60 ors1 is null

;

原文链接
本文为阿里云原创内容,未经允许不得转载。

MaxCompute 挑战使用SQL进行序列数据处理相关推荐

  1. mysql sql使用序列_SQL 使用序列

    SQL 使用序列 序列是根据需要产生的一组有序整数:1, 2, 3 ... 序列在数据库中经常用到,因为许多应用要求数据表中的的每一行都有一个唯一的值,序列为此提供了一种简单的方法. 本节阐述在 My ...

  2. sql server序列_SQL Server中的序列对象

    sql server序列 Sequence objects are used to sequentially generate numeric values. They were introduced ...

  3. sql server序列_SQL Server中的Microsoft时间序列

    sql server序列 The next topic in our Data Mining series is the popular algorithm, Time Series. Since b ...

  4. sql server序列_SQL Server中的序列对象功能

    sql server序列 序列介绍 (Introduction to Sequences) 序列是SQL Server 2012中引入的用于密钥生成机制的新对象. 它已在所有版本SQL Server ...

  5. sql server序列_在SQL Server中实现序列聚类

    sql server序列 In this article, we will be discussing Microsoft Sequence Clustering in SQL Server. Thi ...

  6. sql server序列_SQL Server中身份和序列之间的区别

    sql server序列 In SQL Server, both the SEQUENCE object and IDENTITY property are used to generate a se ...

  7. oracle sql语句序列,Oracle SQL之 序列使用限制

    Restrictions on Sequence Values You cannot use CURRVAL and NEXTVAL in the following constructs: ■ A ...

  8. Oracle sql创建序列sequence

    知道的创建表序列的用途是当建立表的时候,Oracle不像Mysql一样会有自动主键增长AUTO_INCREMENT,所有如果需要主键自动增长的效果,Oracle提供了序列sequence方式. 创建序 ...

  9. oracle sql语句序列,Oracle SQL:使用Select语句插入序列

    假设您要在按序列生成密钥之前对数据进行分组,那么就像您想要的那样 INSERT INTO HISTORICAL_CAR_STATS ( HISTORICAL_CAR_STATS_ID, YEAR, M ...

最新文章

  1. 如何理解IIS 7的两种应用程序池的管道模式(Managed Pipeline Mode)
  2. xml节点的添加和删除
  3. HDU - 6315 Naive Operations(线段树+思维)
  4. websocket binary 数据解析_WebSocket实现原理相关知识点
  5. 将1bpp的bmp图像存储为1bpp或者2bpp的tiff格式
  6. [架构] 分布式和集群的区别
  7. python 进程和线程
  8. android edittext禁止输入特殊字符,Android EditText禁止输入空格和特殊字符
  9. Keepalived配置文件详解
  10. TCP/IP四层模型及各层协议首部详述(包含IOS7层)
  11. java错误页面_java自定义错误页面实现方法
  12. [解决方案]WebAPI+SwaggerUI部署服务器后,访问一直报错的问题
  13. c语言交换字符串,C语言中怎样交换两个字符串?C语言中怎样交 – 手机爱问
  14. NClay框架AOP功能简介
  15. (百看不如一练系列)整理的40个前端练手项目|||实践出真知
  16. 数学建模论文题目优选专业题目128个
  17. 【英文学术论文写作 | 笔记】第一讲 学术研究与英文学术论文写作概述
  18. git本地项目连接私人远程仓库以及遇到的问题
  19. Python3爬虫 爬句子迷
  20. OSPF实验———Secondary Address

热门文章

  1. collector list 多个分组_Java 8嵌套(多级)分组依据
  2. 当前操作系统缺少黑体等字体_从零开始开发一个操作系统
  3. select 移动端 第一个无法选中_总结在移动端碰到的坑
  4. 干货丨总结5类面试官特点和应对方法
  5. 【LeetCode笔记】剑指Offer 37. 序列化二叉树(Java、二叉树、序列化、BFS、队列)
  6. 用户表如何区分普通用户和管理员_Gate.io 比特百科:什么是ETH 2.0及普通用户如何参与ETH 2.0质押挖矿...
  7. leetcode51 --- solveNQueens
  8. leetcode 142 --- linked-list-cycle-ii
  9. vscode angular智能提示_【线下活动】手把手教你玩转 VS Code 插件开发
  10. android 网络连接 网络是否可用,Android 使用ping判断网络/WIFI连接是否可用