每周给我10分钟,我给你一个Flink SQL 菜谱——甜点:数据过滤

每周给我10分钟,我给你一个Flink SQL 菜谱——甜点:数据过滤_第1张图片

 清风的第 04 篇 Flink SQL 分享

太卷了,太卷了,风清李面试回来后,和自己的好基友不停地吐槽,面试造火箭,入职后拧螺丝。

李被三个问题给难住了。

第一个问题是什么是关系代数?

第二个问题是 sql 过滤的原理是什么?

第三个问题是如何用 sql 实现证券交易能量指标的计算。

01 此处不留爷,自有留爷处

上个月的版本发布,周末的加班,组长的 PUA,让李有深深的危机感,有几个晚上竟然醒来后就瞪着个大眼睛等天亮。生于忧患死于安乐的风险意识告诉他,得到市场上去看看,看看自己有几斤几两。趁着周末的时间,他赶紧写了写简历。

简历上,他这样写到:

①经验丰富:多个大厂工作经验,丰富的数据中台项目经验。

②专业能量强:系统架构师,技术工具箱里放着 AI 工程化、ModelOps、Flink 实时计算、数据仓库、微服务架构、领域驱动设计、DAMA 数据治理 CDGA、多语言编程、多元思维模型等。

③善于学习:一年读书五十本+,快速地从自己和他人的错误中学习能力。

一份漂亮的简历太重要了,很快,就收到了某厂的面试邀约。

02 奇葩的面试题

踌躇满志,志在必得的李来到了面试现场,面试官是一个瘦瘦的,脸黑黑的,眼角看上去还有两圈熊猫眼,李感觉这,这,这加班也太猛了吧,这哥们看起来像个 95 后,怎么一脸疲惫呢,这卷得也太夸张了吧。

面试官正低头认真的看着李的简历,忽然猛的一抬头,发现李正盯着他看,刚好发现李刚要收回的鬼笑的表情,面试官眼睛往左转了转,一个冷笑从嘴角飘过,这小子,竟敢对我无理,我给你个下马威。

面试官左手拿着简历,严肃地说到:这样,我们也不搞什么自我介绍了,我们需要个来了就能上战场的人,我也就不多客套了哈,避免浪费大家时间。我们项目这个月底,领导下了死命令必须正常甚至提前上线。现在有一个需求是这样的:

业务需求:现有 AR、BR 两个指标需要计算,这个属于能量指标中的一种,指的是人气和买卖意愿指标。证券市场中买卖双方力量的强弱直接影响着价格的上涨或下跌。能量指标往往用于刻画多空力量的对比,是分析股市多空双方力量对比、把握买卖股票时机的一种中长期技术分析工具。

指标的计算公式是这样的:

AR=(当天最高价—当天开盘价)26 天之和 /(当天开盘价—当天最低价)26 天之和 × 100。

BR=[(当天最高价—昨天收盘价)和 0 的最大值]的 26 天之和 / [(昨天收盘价—当天最低价)和 0 的最大值]的 26 天之和 × 100。

你用 Flink SQL把这个指标给写出来,并解释一下数据过滤的原理,为了简化一下复杂度,只考虑板块为医疗的股票就行。

李看着这个需求,来时的一脸傲气早已荡然无存。这 AR 就是那个增强现实吗?不太熟悉呀,我对那个 VR (虚拟现实)倒是还熟悉一点,之前还去好基友那里体验过,戴着 VR 眼镜,打游戏,那简直不要太爽。不过那都是虚拟的,现实是他现在要把这个刀杀的面试官一来就出的面试题给用代码写出来。

时间一秒一秒地过去,李坐在座位上,感觉热不可耐,背上已经有点湿湿的感觉。30 分钟,终于憋出了:

select sum(当天最高价—当天开盘价) from price where trade_date >= LOCALTIMESTAMP - 26*24*60*60 and asset=medical;

面试官说,先写到这里吧,我们都知道 flink sql 底层是用 calsite 来优化解析 sql 的,用到的是关系代数的原理,我就问三个问题哈。第一什么是投影?第二什么选择?第三 where 条件是怎么实现数据过滤的?

李支支吾吾,说东扯西,讲了一大堆不着边际的话,最后糊里糊涂地回了家。

03 闭关修炼

这个当头棒喝来得如此干脆,打得李有点怀疑人生,我他妈到底适不适合写程序呀。

面试回来的周末时间,李躺在床上过去了不愿意出门,直到网格员打电话来催他去做核酸,才无精打采的下了楼。核酸的队伍排得长又长,李没心情看手机,听着旁边两个穿着拖鞋的两个中年大叔在聊天。

矮胖大叔说到,之前他们那里有个老板,花了 60 多万转手了一个店,各种证件都办齐了,重新装修的材料也购买到货了,不料,警察上门了,直接叫停了正在装修的工人,说疫情期间,为了人民的身体健康,防止疫情扩散,需要停工一个月。老板直接快要崩溃了,妈的,我花了几十万,投入了大半身积蓄准备做点事,结果你一句话就让我 60 万打水漂,你们早干嘛去了?在我办证的时候为啥不说?非得我钱花了后才说?

老板深知胳膊拧不过大腿,蹲在店门口,无力地望着天,地上堆着一只又一只烟的尸体。瘦高大叔附和到,哎,太惨了。

这聊天深深地触动了李。妈的,老百姓太苦了,我要用科技给人们带来更好的生活,用科技的力量来引导执法者向善。回想前天的面试,李为自己的表现而深感懊恼,我辈岂是这样一个小小的挫折能打趴的?想当年,来大深圳,不就是为了出人头地,活出个人样,为世界做一点自己的贡献吗?

做完核酸回到家,从书架上抽出俞敏洪的《我曾走在崩溃的边缘:俞敏洪亲述新东方创业发展之路》,一口气读完了。写下了下面的话:

在绝望中寻找希望。

蜗牛虽然不能像雄鹰一样一下飞到金字塔顶,但是它的坚韧,照样可以带它看到更高的风景。

成功并不能掩盖我们曾经遇见的困难与困惑——现实总是比电影更精彩。

不是被逼到绝境走投无路时,谁都想安逸地过一辈子,所以才说危机里面都是转机。不畏风雨,熬过极暗过后会是黎明。

工作上。到市场上做自我检验后,发现了自己有几斤几两,李放弃了幻想,开始务实,做事也脚踏实地地干,不再向之前那样总是表现的牛气冲天,一副老子天下第一的样子,你们都不配给我安排任务。

学习上。以上周的面试题为纲,深挖 Flink SQL 数据过滤涉及到的各种知识点。

第一什么是投影?

投影针对的是列。关系代数运算中的投影是对关系进行的水平分割。投影运算是针对属性进⾏选择的运算,也就是投影是选择出符合条件的⼀列,并且会⾃动取消某些⾏。如行情表里有股票代码、开盘价、收盘价、最高价、最低价、交易价、交易时间等,使用投影可以只筛选股票代码、开盘价。如果表里面有相同的开盘价和交易时间,投影会去重留下一条。用关系代数可表示为:

每周给我10分钟,我给你一个Flink SQL 菜谱——甜点:数据过滤_第2张图片

 

第二什么选择?

选择针对的是行。选择也称之为限制。选择运算是查询符合条件的⾏。如行情表里有股票代码、开盘价、收盘价、最高价、最低价、交易价、交易时间等,需要筛选股票代码为 60318 的股票行

情,用关系代数可表示为:

每周给我10分钟,我给你一个Flink SQL 菜谱——甜点:数据过滤_第3张图片 

总结:

关系代数是以关系为运算对象的一组高级运算的集合。由于关系定义为属性个数相同的元组的集合,因此集合代数的操作就可以引入到关系代数中。关系代数中的操作可以分为两类:传统的关系操作,并、差、交、笛卡尔积(乘)、笛卡尔积的逆运算(除);扩充的关系操作,对关系进行垂直分割(投影)、水平分割(选择)、关系的结合(连接、自然连接)等。

在集合运算里,我们知道有求交集、并集、差集、补集的运算交差并补,为什么数据库的关系代数只选择了并和差呢?答案是交、连接、除都可以通过基本的运算推导运算出。所以数据库的关系代数只需满足五元组就行了:(并,差,笛卡尔,投影,选择)。

1、并,设有两个关系R和S,它们具有相同的结构,R和S的并是由属于R或属于S的元组组成的集合;

2、差,R和S的差是由属于R但不属于S的元组组成的集合;

3、笛卡尔积,两个集合X和Y的笛卡尓积,又称直积,表示为X与Y相乘,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员;

4、选择,从关系中找出满足给定条件的那些元组称为选择;其中的条件是以逻辑表达式给出的,值为真的元组将被选取;

5、投影,从关系模式中挑选若干属性组成新的关系称为投影。

五个关系代数操作分别是:并、差、笛卡尔积、投影和选择。它们组成了关系代数完备的操作集。

第三 where 条件是怎么实现数据过滤的?

来一段说写就写的代码。

创建表:

drop table if exists t_price;
create table t_price(
stock_code STRING,
stock_name STRING,
currency_code STRING,
exchange STRING,
yclose DOUBLE,
topen DOUBLE,
tmax DOUBLE,
tmin DOUBLE,
latest_price DOUBLE,
trading_volume INT,
transaction_amount INT,
trade_time  TIMESTAMP(3),
trade_date   TIMESTAMP(3),
WATERMARK FOR trade_time AS trade_time - INTERVAL '5' SECONDS
)WITH (
'connector' = 'faker',
'fields.stock_code.expression' = '#{regexify ''(SZ|SH|BJ|HK)-[0-9]{6}''}',
'fields.stock_name.expression' = '#{Commerce.productName}',
'fields.currency_code.expression' = '#{regexify ''(EUR|USD|GBP|RMB)''}',
'fields.exchange.expression' = '#{regexify ''(SZ|SH|BJ|HK)''}',
'fields.yclose.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
'fields.topen.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
'fields.tmax.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
'fields.tmin.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
'fields.latest_price.expression' = '#{Number.randomDouble ''2'',''1'',''150''}',
'fields.trading_volume.expression' = '#{Number.digit}',
'fields.transaction_amount.expression' = '#{Number.digit}',
'fields.trade_time.expression' = '#{date.past ''30'',''SECONDS''}',
'fields.trade_date.expression' = '#{date.past ''5'',''SECONDS''}',
'rows-per-second' = '100'
);

创建资产类别表:

create table t_asset(
stock_code STRING,
asset STRING
)WITH (
'connector' = 'faker',
'fields.stock_code.expression' = '#{regexify ''(SZ|SH|BJ|HK)-[0-9]{6}''}',
'fields.asset.expression' = '#{regexify ''(medical|education|fund|bank)''}');
--EXPLAIN PLAN FOR 执行计划
SELECT sum(P.tmax-P.topen) as total
from t_price P
join t_asset T
ON P.stock_code=T.stock_code
where SECOND(P.trade_date) >= (SECOND(LOCALTIMESTAMP) -26*24*60*60)
and T.asset='medical';

经过上述操作后得到了一个树状结构的逻辑执行计划,根节点对应最上层的 Select 语句,叶子节点对应输入表 t_price 和 t_asset 的 TableScan 操作,Join 和 Where 条件过滤 分别对应了 Join 和 Filter 节点。

查看执行计划:

== Abstract Syntax Tree(抽象语法树) ==
LogicalAggregate(group=[{}], total=[SUM($0)])
+- LogicalProject($f0=[-($6, $5)])
   +- LogicalFilter(condition=[AND(>=(EXTRACT(FLAG(SECOND), $12), -(EXTRACT(FLAG(SECOND), LOCALTIMESTAMP), *(*(*(26, 24), 60), 60))), =($14, _UTF-16LE'medical'))])
      +- LogicalJoin(condition=[=($0, $13)], joinType=[inner])
         :- LogicalWatermarkAssigner(rowtime=[trade_time], watermark=[-($11, 5000:INTERVAL SECOND)])
         :  +- LogicalTableScan(table=[[default_catalog, default_database, t_price]])
         +- LogicalTableScan(table=[[default_catalog, default_database, t_asset]])

从上到下的执行顺序是:逻辑执行计划-》物理执行计划-》Excution 执行计划。为了能更好的和开源的同行们深入交流学习,李把自己的代码放到GitHub了,具体的仓库地址是:https://github.com/cjjxfli/real-datawarehouse-cookbook.git

可视化后如图所示,这是优化器开始工作的初始状态。

每周给我10分钟,我给你一个Flink SQL 菜谱——甜点:数据过滤_第4张图片

 

project 对应执行计划第 3 行,filter 对应执行计划第 4 行,join 对应执行计划第 5 行,scan 对应执行计划第 7,8 行。

Flink SQL 的解析流程总结:

 

以上,就是李对 Flink SQL 数据过滤的总结。

被社会铁锤砸下之后,李醒了。原本想着把这些知识点系统的,深度的过一遍后,再投石问路,不过学习完这些技术后,李曾经那颗想要迫不及待离开现在公司的心已经没那么强烈了。他已经明确他要用科技的善来治社会的恶。

破山中贼易,破心中贼难。难也要干,先从工作上开始修行。

李深知自己之前粗鲁的表现,在组长那里没什么好印象。为了缓和自己和组长的关系,让组长在他翅膀没长硬前,不要去告谕状,先混口饭吃,李接下来的日子表现得出奇的积极主动,去理解组长,其他同事想要什么,践行知彼解己,抢着去做事。

05 打靶归来

人生就是这么奇妙,李卧薪尝胆,收起菱角,刻意练习做人讲灰度,做事讲原则,讲方法,践行积极主动,要事优先,知彼解己,付出不亚于任何人的努力。每天都在读书,写作,看源码,写源码,每一天都这样度过。

转眼间,年底的考核如期而至,李竟然破天荒的没有像去年考核时不断的跟不同的同事吐槽公司的,部门的种种不是,心态好得出奇,好像一切跟自己无关一样。

你能过好,一定是有人希望你过得好。

今年的考核排名出来后,李破天荒的在拿了个 A+ 。组长的评语是这么写的:

该同事在本年度工作中,参与了 AI 中台、数据中台、业务中台的产品研发与项目交付,需要产品经理时能迅速承担起产品经理的职责带领团队有条不紊的展开工作;需要项目经理时,能迅速以项目经理的角色带领团队加班加点,攻坚克难准时完成项目的交付,获得客户的好评;需要架构师时,能不停的学习架构知识,高屋建瓴的从不同的视角进行架构设计,有效保障了中台的模块化,配置化,容器化,可扩展,服务之间松耦合,服务内部高内聚。综合来看,无论在哪个岗位,工作兢兢业业、任劳任怨、作风优良、勇往直前、敢打敢拼。

面对突然降临的幸福,李受宠若惊,叹息到以前拼了命的去争一个好的绩效,却总是以排名 C 收场,今不再刻意去追求了,A+ 却从天而降。工作真的就是修行,不要刻意去追求什么,有目标就行。

譬如有个代码,你只想做到80分,但经过努力做到了99分。

再譬如很讨厌某个同事,但修炼心性后和他成了最佳搭档。

再譬如某个事想拖延到周末完成甚至摔锅给其他人,但提前完成了,解决了问题锅也就不存在了。

再譬如某个事领导说或做得不对,自己通过某些技巧帮助领导纠偏,最终团队受益,一起得到了成长。

正如王阳明说到:

立志用功,如种树然。方其根芽,犹未有干;及其有干,尚未有枝。枝而后叶,叶而后花、实。初种根时,只管栽培灌溉,勿作枝想,勿作叶想,勿作花想,勿作实想。悬想何益?但不忘栽培之功,怕没有枝叶花实?

是的,李静下心来,踏踏实实,兢兢业业,不挑活不甩锅,同事问问题找他他都竭尽所能的去帮助同事,短短一年的时间,同事们眼中的那个好高骛远,心比天高命比纸薄的李彻底改头换面,变成了一个优秀员工,相信假以时日,他会走上卓越之路。他会实现他的科技向善的初心(发心)。

每周给我10分钟,我给你一个Flink SQL 菜谱——甜点:数据过滤_第5张图片

 

今天的分享就到这里,如果您觉得有用的话,记得关注哦,关注后才能第一时间看到清风君的每周分享。

<===> END <===>

每周给我10分钟,我给你一个Flink SQL 菜谱——甜点:数据过滤_第6张图片

 

你可能感兴趣的:(flink,sql,大数据)