个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview
回顾
默认你已经看过之前那篇风控系统指标计算/特征提取分析与实现01,Redis、Zset、模版方法。
其中已经介绍了如何利用redis
的zset
结构完成指标计算,为了方便这篇文章的介绍,还是在正式开始本篇之前回顾一下。
时间窗口
zset
是redis
中的一种数据结构,表示有序集合,正因此我们可以利用其做时间窗口来计算指标,value
为事件标识,score
为事件时间戳。
如下图表示次数、关联、求和类型各两条指标在时间窗口下随着时间分布,其中的黑点也就是事件,散列且线性的分布在时间窗口中。
指标字段
关于指标我们需要哪些配置?
来看指标字段有哪些:
type
:指标类型,有次数计算、关联次数、最大值、最小值、求和等等calcField
:计算字段,必须为数值类字段,而且仅用于计算类指标,如次数统计类指标计算的就是事件本身,不需要设置计算字段winSize
:窗口大小,与其讲是窗口大小不如说是窗口单位,取值有M/d/H/m/s
,表示月/天/时/分/秒timeSlice
:时间片,与窗口大小对应,单位为秒winCount
:窗口数量,与窗口大小组合起来是整个指标计算的窗口大小winType
:窗口类型,目前取值只有last/cur
,表示最近或是当前masterField
:主字段,如:计算某客户登录次数,主字段就是客户唯一标识salveFields
:从字段们,可以是多个,如:计算客户在某设备的登录次数,主字段是客户唯一标识,从字段是设备唯一标识sceneType
:场景类型scenes
:场景,与场景类型组合起来用于隔离的指标
计算流程
1、对于未知的输入,根据指标配置计算。
如下图,未知的事件经过指标计算在指标时间窗口上记录。
2、时间窗口记录事件,并设置过期时间。
如下图,横轴表示时间,黑色的点是已有事件记录,竖线表示当前时间,红色是当前这笔事件的记录。
因为Redis
只能给整个key
设置过期时间,所以要整体上要设置过期时间。如果前面配置的窗口类型winType
是last
,表示最近,那么设置的过期时间就是timeSlice
*winCount
;如果设置的是cur
,标识当前,那么设置的过期时间就是timeSlice
。
3、窗口移动并计算结果。
如下图,竖线表示当前时间,红框表示窗口,根据指标类型计算窗口内事件的值就好。
问题
已知指标都是随事件的发生实时计算而来的,指标的一些字段是一次创建后不可更改的,如上梳理的type
:指标类型、calcField
:计算字段、winSize
:窗口大小、timeSlice
:时间片、winCount
:窗口数量、winType
:窗口类型、masterField
:主字段、salveFields
:从字段们、sceneType
:场景类型、scenes
:场景,都是一次创建不可更改的,因为一旦修改了其中的字段数据相对就不准确了。
由此会产生一个严重的问题,两种场景下都会出现很大问题。
1、新创建的指标并不能及时使用
因为新创建的指标并没有任何数据,这时并不能用。什么意思?如我需要设置一个规则“最近90天没有登录的账号要进行一次短信验证”,那么我设置的一个指标是“最近90天账号登录次数统计”,设置规则为“最近90天账号登录次数统计”为空则决策结果为“短信验证”。这个新的指标并没有跑已有数据,那么这就是不准确的,直接上线指标那么全部账号都将会多一次短信验证,短信产生的费用不讲,用户带来的体验也是很差的。
2、修改已有指标会错误
对于已有的指标通常都会设置不允许更改的字段,如上,这个并不需要过多解释了。那么如果已有的指标设置错了,但又不可更改,那么这个问题又回到上面了👆
所以,总结问题的解决方案就是:对于新增和修改的指标能支持对已有数据的重跑。
正向计算
正向计算就是和普通的流式实时动态计算没有差别,虽然将是这么讲,但是其实涉及到的是整体数据存储的设计考验。前面很多篇文章也讲了,风控数据最终会通过Kafka
存储在ElasticSearch
中,所以数据是有的,关键是怎么取,在何时跑数据。
另外的问题随之产生了,如何避免对生产数据的影响并保证指标的准确性。
如:刚刚创建的指标“最近90天账号登录次数统计”想要对历史数据重跑。
如下,指标创建时间触发了历史数据重跑,那么就是对于历史90天的数据进行重跑计算指标,开始时间和结束时间就是[T-90day,T]
需要注意此时指标状态要保证不参与生产任务,不然数据会更乱。
生产任务不会因为你重跑而停止啊!假如在指标重跑完成也就是图中T+x
的时候,其实生产已经跑到了T+n
,那么指标数据还是少了n
的这段时间,怎么办?
其实我上面埋了一个小坑。
就是这句话“需要注意此时指标状态要保证不参与生产任务,不然数据会更乱”,其实这句话并不是没有道理,很合理。但是其实是可以放开的,啊?为啥呀?
如下,重跑任务和上面一样其实也只是蓝色的部分,但是如果放开了指标产于生产任务,那么指标就和生产任务步调一致,不会有差别。已有数据只是迁移,本身就和生产有时间差,而且记得我们的计算方法吗?Redis
的Zset
啊,Set
啊!
反向查询
本来我还以为这是一条可行的路,但是细致思考后,好像确认了,这是一条不可行的路。
上面的图我用一下,可以知道生产数据是未知的,不管是指标还是后面的Kafka
、es
存储,都是为了结构化数据,其实感觉编程的本质都是这样🤤
那么既然对已有结构化数据的查询会不会对于历史数据重跑意义更大,而且更简单呢?
还是这个指标“最近90天账号登录次数统计”,我直接按照指标配置的条件查历史数据将数据塞到指标里不是更简单?
的确如此,查询要比生产任务跑出来的指标更直观且简单。
关键的问题在于问题的关键!😂
还是那句话数据是未知的!如果已经指标需要计算的账号,那么查询历史数据就好,但是问题根本就不知道要计算的账号和条件。如果要通过查询的方式,那就必须对要计算的目标先搞清楚,但是本身指标就是多变的不确定的东西就更难搞了。
也许讲的有些抽象,具体一点吧。“最近90天账号登录次数统计”中账号就是未知的${账号}
,如果要计算那么就要先从历史数据确定90天内有记录的账号,然后才是查询历史数据这些账号有多少次登录,塞进指标里。
注意这还只是因为“最近90天账号登录次数统计”指标设置的比较简单,要是遇到计算字段、主字段+从字段、还有很多变量的,很难有一套统一的方法计算的。
写在最后
拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。
个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview