00:00
现在已经知道用process function自定义的kid process function怎么样去处理这样一个呃,风控类的指标了,恶意登录事件的检测啊,那前面我们用了两种方式,一种是注册定时器,然后等到定时器触发的时候去判断,呃,连续登录失败的次数是不是达到了这个标准,那另外一种方式呢,是不注册定时器时效性更更好,就是来一个事件就立刻判断一次,但其实大家也会发现这里边其实还是有些问题的,因为这里边我们判断的时候按照事件触发的话,这是不是相当于我们的判断就必须严格依赖于事件到来的顺序啊,大家想一下,当前我这里边有这个数据直接进来了,对吧?那假如说我在判断这个到底是成功还是失败的时候,我有看他的时间戳吗?这里边并没有判断对吧,那大家会想一下,我们现在这是真的是连续三次登录失败对吧?那假如说我中间插入了一个一次登录成功的话,会有什么效果,如果说这里边来了一个success,这会是什么样的?
01:13
这当然这个4243之间就不报警了,对吧?呃,正常来讲肯定是这个就不报警了啊,然后这个4344,这可能还是会正常报警的,那假如说。大家想一下啊。这里边是不是我这里面有可能有乱序数据啊。那你想我如果在四三和四四之间也插入一个四二的话,这个会出现什么情况报警,这是不是就相当于都不报警了呀?那我们重新运行一下,大家看看现在有没有报警输出啊,当前我是在相当于三次feel中间直接插入了两次success的这个数据啊,那大家看一下当前到底有没有这个报警的数据。按照我们的定义,至少这个4344应该报警对吧,大家看这里边就不报警,然后另外当然大家还可以考虑,我现在不是允许这个三秒的乱序嘛,前面那个watermark延延迟时间给了三秒吗?那假如说这里边我给一个呃,给一个4545时刻的一个登录成功,下面给一个四六时刻的登录成功,这是不是相当于应该不影响我们424344连续的这三次登录失败啊。
02:23
大家想想是不是这应该完全没影响,但是如果现在我要是再做一个检测的话,会怎么样?他是不是还是对直接就会什么什么都不输出,检测不到啊。啊,所以大家会想到这里边就是乱序数据对他的影响,就会导致打乱我们中间的这个处理流程,对不对。哎,那有同学可能就想到了,那假如说如果是前面我们那个注册定时器的那种方式,不按这个事件出发的话,可以解决这个乱序数据的问题吗。其实也不能,因为大家想前面我这个乱序数据来了的时候,只要是success,它是不是就把那个定时器直接清空了呀,那是不是更不报警啊。
03:04
哎,所以之前我们做的这两种情况都没有办法实现对于乱序数据的处理,那假如说现在我们这个场景,这就是流失处理里边有乱序数据,那怎么办呢。诶,我们可以想到一个实现思路,就是可以在之前我们这个事件触发的后面的这种改进的基础上啊,再去大家想我是不是还是在这个基础上再去注册一个定时器,只不过这个定时器应该要怎么样呢?呃,就是比方说啊,我这里边的数据是来了一个,呃,就是四二的数据,然后来了一个四三时候的出数据,对吧?那大家注意我处理这个四二时候的数据呢,不是说这个时候就判断当前它是一个feel,然后接下来四五来了之后,马上就判断这是feel,后面来了一个success,因为这中间是不是有可能要插入乱序数据,所以我是要按照什么来判断的。我得按照oma来判断呀,所以就是说我当前应该要注册,比方说四二来的时候,我就注册一个四二时间的定时器,那么它的触发是不是就应该是等到water mark到达四二的时候才会触发啊?
04:17
那么到这个时候我才判断当前这个四二哦,他是真的是第一次登录失败对吧?呃,就之前我们没有那个登录失败,呃,那现在他是第一个登录失败,然后后面这个四五来了之后呢,比方说现在我们那个water mark延迟三秒对吧,那他来了之后,现在water只到四二,他会注册一个四五时候的定时器,我是只有到四五时刻才会去处理之前四五时候发生的这个success登录的事件。所以大家会发现,现在如果说Outlook只到四二的话,这个success是不是相当于对我的状态没有影响啊?如果你要这么做的话,那就相当于没有影响了,对吧?就相当于我还是要延迟出发,还是要等着,我就是按照那个water mark的延迟时间来等待它。
05:04
那大家想接下来如果要是乱序数据来了,843来了的话,这个时候water mark还是四二,那那其实这个数据是不是我还是不处理先缓存起来啊,但是等到后面846来的时候,Watermark到了843,这个时候我是不是就应该检测到哦,原来前面是不是4243连续两次在两秒钟之内连续两次登录失败啊,而且我可以确信是不是四三之前的数据都不来了。因为watermark的含义是不是就是要说在这之前的数据已经都到齐了,哎,所以大家看,如果你用这种方式去做的话,那是可以把它做一个处理的,但是大家就想到这个太复杂了是吧,这光听一听这个思路都非常的绕啊,非常的复杂,而且我们前面也看到了,这还仅仅是连续两次登录失败,那之前我们说如果你要是连续三次登录失败呢,五次十次登录失败呢?那本来这个逻辑if else已经是绕晕了,你还要各种注册定时器是吧,然后去判断当前它怎么去处理,所以在这种特别复杂的场景下,复杂事件的这种处理的场景下,那我们直接定义process function放大招,它理论上是能搞定,但是好像就有点不划算,那我们自然就想到了,有没有一个更加简单的易用的,帮我们把这个底层的东西都包起来的一套机制,直接能够搞定这种场景呢?复杂事件的场景呢?
06:31
哎,这就是接下来要给大家引入的一个新的部分,就是所谓的cep啊,Cep的话全称它其实CP是个缩写啊,全称是complex event processing,所以它的含义其实就是要处理复杂事件,对吧,复杂事件处理。啊,那么CP大家可以认为是flink官方给我们提供的一个高层级的一个库啊,它是一个library,那那么我们在使用的过程当中呢,本身flink源码里边是不带着的,要用的时候就还得做一个做一个引入,对吧?所以大家看前面这里边我们是需要引入一个dependency的,这里边引入的这个模块就是flink cp后面跟上skyla的版本,然后当前呃,这个跟flink的版本是一致的,对吧?啊,直接把这个引入一点点一就可以了。
07:21
先在pop文件里边把这个做一个操作,呃,当然了,当前就只有在这个模块我们用到了cep啊,所以只在这儿写就可以了,Depends把这个dependency引入。呃,那接下来呢,我们还是在代码里边新建一个detect,下边新建一个class,当前我这个就叫做logging field with cep,接下来我们就用这个CP给我们提供的工具看一看到底怎么样去处理这个连续登录失败的事件的检测啊,那首先呢,我们还是前面的流程,其实大家想到应该都差不多对吧?啊,就是这个过程我就不重复去写了,直接把前面的这个主体流程都抄下来啊,Main方法直接抄下来。
08:10
直接copy到这,呃,然后在这里边我们把这个job name改一下啊,这个是detect with cp job啊,然后另外前边这里边我们去获取,呃,获取这个class的时候,获取这个resource的时候,我也只用当前的这个类就可以,对吧,以自己作为一个标准啊,啊这还是创建执行环境,从文件里面读取数据,然后map成po类型,接下来是这个分配时间出和water mark啊,那接下来我们就是。不是自定义这样去处理了,对吧?接下来我们要做的事情就是按照这个P的模式去做处理了,那这里边的步骤我可以先列出来,CP怎么样去处理事件呢?这里边有一个非常重要的概念,就是要定义一个匹配模式,所谓的所以接下来这有点像SKY里边我们不是讲过那个语法有那个模式匹配吗?呃,有点像那个那个过程,这里边就是我先定义一个事件先后发生的一个模式,然后把这个模式应用到对应的那个数据流里边去,就可以检测符合这个模式的相关事件啊,那就是如果说我要定义当前这个事件发生就是连续登录失败,那我如果应用到那个流上,检测出来的就是连续登录失败的那些事件,然后接下来我再把它提取出来,做一个做一个处理输出报警信息就可以了,对吧?诶所以整体来讲这个思路还是比较简单的,所以首先是定义一个匹配模式,然后第二步呢,要做。
09:43
的操作是啊,就是将。呃,匹配模式应用到数据流上对吧?呃,然后相当于就是这个要得到一个特殊的一个类型,这个叫做一个pattern stream,就是一个有点像一个模式流,或者叫就是就是符合某种标准的啊格式的这样的一个定位出来的这个流,对吧?我们要检测特定的那个事件组合了,然后下面的第三步,第三步的话,那就是我们要从这个patternon stream里边检出符合匹配条件的。
10:31
呃,事件事件组对吧,或者我们叫复杂事件,然后进行进行转换处理,那我们最终当然得到的就是一个就是报警信息了,对吧?得到报警信息,这就是我们简单的一个CP3步走的过程啊啊,那首先这里边这个定义匹配模式的时候,大家要注意我们想要的模式是什么呢。
11:04
其实很简单,就是是不是前面先来了一个事件,应该是第一次登录失败对不对,我们把它叫做first few,对吧?First few后边是不是接着紧接着就会发生一个,呃,就是second,对不对,Second。的feel,哎,我们想要的就是这样的一个模式,然后另外我们还有要求,这俩发生是不是在在多长时间内是两秒范围,两秒时间内这个才生效对吧,超过两秒的话,这个就无效了啊,所以接下来我们还可以定义一个,它要求是比方说WITHIN2秒之内对吧?啊,两秒范围内啊,所以这就是我们想要得到的这个当当前定义的这个模式嘛,先检测到一个登陆室外事件,然后又检测到一个登陆室外事件,他俩要求还必须在两秒钟之内,这是这就是所谓的我们的模式。大家看一下这个怎么定义啊,呃,那这里面我定义的就是要用到,呃,大家看,注意不要用那个Java u的那个正则里面那个patternon,对吧,我们要用的是flink cep里边的这个pattern,然后pattern,大家看接下来它必须调的一个方法叫做begin begin的话,顾名思义我们就知道当前是不是就定义的就是开始这个事件啊。
12:22
啊,所以在这里边我直接把这个事件的名称可以直接给在这就叫做first few,我们不是想把第一个失败的事件叫做first few吗?当前这就是第一个检测到事件的那个名称。啊,当然了,这里边我们还应该定义一下它的类型,你到底处理的这个数据啊,到底是什么样的类型,这个类型呢,泛型是写在前面的啊,因为大家看到这个begin啊,我先把这个写出来,我们当前的数据类型应该是logging logging event对吧?Logging event,然后大家看到这里边的这个begin啊,它本身是一个泛型方法,对不对啊,所以我们在调用的时候,可以直接在前边把当前它这个对应的这个类型泛型啊,直接可以写出来。
13:08
当前我要处理的是logging。这是begin first few,那大家想,我定义在这是只给了一个名称而已啊。那弗Li要检测的话,他怎么知道这是一个这是一个logging field呢?所以后边我是不是还得给他的条件啊,所以后边我再跟上一个当前的条件,这个条件就是where对吧?用一个where来表示当前的条件,大家在里边要去给的是一个可迭代的一个condition一个条件啊,那其实这里边我们不需要可迭代那么复杂,我只要给一个simple condition简单条件就行了,因为其实大家知道我现在要的是个什么,不就是要筛选当前它的那个登录状态等于field的那种情况吗?啊,所以大家看这是不是相当于就是一个filter啊。哎,所以你看里边实现的一个方法啊,就是一个filter,这跟我们那个过滤器是不是一样啊,啊对吧,所以是差不多啊,就是我们在外面的那个filter,在这儿是要实现这样一个方法,呃,那我把这个当前的条件之前我们在。
14:10
Logging file里边判断的这个条件,Fair equals value,点这个,呃,Get logging state是不是直接就把这个copy到这里就可以了,大家想想是不是这样啊,当前这个也叫value嘛,我就判断它的那个loging状态啊,登录状态是否等于feel,如果等于few的话,我检测到了,它就叫做第一次失败,对吧?诶,大家看这就是我定义的呀,然后注意这是begin,这是当前开始对吧?所以它才叫第一次登录失败,那后边是不是还应该有第二次登录失败呀,对吧?这才叫连续登录失败嘛啊所以这里边接下来我要做的一个事情是直接点,大家注意它可以有一些。两次的判断,这个就是具具体的这个事件模式之间啊,啊,我可以给一个给一个连接词,比方说我给一个next next大家知道是什么意思,下一个对吧,所以为什么我要next呢?就是因为中间first few后边我可以来一个这个成功的事件吗?
15:14
不可以,对吧,是不是下一个就一定必须得是失败事件我才能成功匹配啊,只要不是,那么就匹配失败,对吧?我就不做报警了,如果要是下一个真的是这个,呃,登录失败的话,那后面我还得加一个限制条件是两秒钟之内对不对,符合这些所有的条件,这就这就是一个我们想要的那个需要报警的信息嘛,哎,所以我的这个模式是这么去定义的,接下来是next,同样后面也可以给一个字符串,给一个名称,当前这个事件的名称,这个叫做second film,然后接下来它是不是也可以去给一个where啊,对吧,给一个简单条件啊,那大家想当前的这个简单的条件是不是还是fair equals value.get loging state啊,这个过程一样,对吧?呃,这个是完全一致的,因因为我们这里面判断的条件都是它的那个登录状态等于fail嘛,只不过就是说先发生什么后发生什么,这个顺序就保证了这是第一次登录失败。
16:14
这是第二次登录失败对吧?诶这就是在这个模式里边给我们定义出来的,然后最后还应该要有一个时间限制,诶那大家想看这个时间限制就叫做V对吧?前面我这里边为什么呃,这为什么这么装,非要写一个英文是吧?啊就是因为这里边的这个方法啊,我们调用的方法它就叫做within,在多长时间范围内,然后大家看里边传的是不是就是那个window time呀,类似于我们手动开开了一个窗口对吧?然后它的那个这个time呢,大家注意,也就是之前我们。在窗口设置时间的时候,给的那个window time.time大家看啊,给的这个必须要给这个API window time下面的这个time对吧,必须要给这个,所以我直接随便给一个。
17:02
呃,比方说当前这个是两秒对吧,这个你也可以选这个毫秒2000啊,这个都一样,我把这个定义出来,当前的这个pattern,我可以叫做这个叫logging field pattern登录失败的这样的一个模式,这就是我们第一步定义了这样一个模式出来。我可以把它对齐一下啊,好,当前这个就是对对齐的状态,那接下来我们就要把这一个模式应用到之前我们的这个数据流上去,Loging stream上去,对吧?然后这里大家要注意一下,我们要应用上去的时候,检测的时候,我是针对所有数据检测吗?又是我们之前那个问题,我我是要针对同一个uz ID里边的数据检测,对吧?我这里面判断的时候并没有判断uz ID是什么,对不对?那大家想我可以怎么样,是不是直接把这个数据流先做一个分组啊,先KBY,然后再应用这样的一个patternon,是不是就相当于只针对当前user ID,然后第一次登录失败,第二次登录失败了啊,所以这个就比较简单啊,那接下来我们要做的操作,这个应用的这个操作啊,是要用cep,大家看这个本身就有一个类叫做cep,对吧?CEp.pattern调这个pattern方法,它里边传递的这个参数呢,可以有两个,一个就是一个daily。
18:24
Stream,这是我们的input输入的这个数据流,后面是不是就是当前的这个pattern啊,啊,所以接下来就是这两个啊,前边的是logging event stream,然后我们要首先做一个K。当前是基于logging event对应的那个user ID去做一个K,对吧,然后另外把当前的那个logging feel pattern传进来,这就是我们想要的。呃,所谓的呃,应用到数据流上得到的一个东西,那大家可以看一下这个得到的类型是什么,这个东西就叫一个pattern stream,对吧,大家看它的类型真的就叫做pattern stream。
19:08
所以它有点像之前我们基于那个data stream进行转换的那个过程,对吧?你比方说像我们两条流做连接的时候,Connect connect起来之后得到的是一个connected,呃,然后接下来是不是再做一个Co map Co Fla map就可以提取出,呃,就是一国两制嘛,得到最后,诶我们真正想要得到的那个转换之后的data stream,或者说我们做分流的时候,是不是那个split,得到的是1SPLIT stream呀,然后接下来再做一个select,对吧,再剪出我们想要的对应的那个分流之后的three,现在也差不多,现在是把之前的那个patternython应用到这个流上,得到了一个patternon three。然后我们点进去看一眼pattern stream里边又能调什么方法呢?这里大家看到它能调的方法其实比较有限,好多都是这个重载的方法对吧?哎,那这里边其实flat select,另外还有一个就是select。
20:02
最后还有一个是process,大家知道process的话类似于是一个process function那样,对吧?啊,它其实就是底层的这个API啊,能得到上下文里面更多的东西,那最一般的这个调用,大家看下面是不是就没有了呀,下面就没了,对吧?最一般的就是一个select,或者是一个select select,那这个操作是不是就类似于之前我们connected streams里边的那个。Map和呃,Co map和Co Fla map呀,对吧?所以这里边的操作基本上是差不多的,所以现在我们要想从里边检出符合匹配条件的复杂事件,怎么检出呢?当然就是要调一个select方法对吧?啊,所以我们直接把这个pattern stream啊,直接调一个select,或者你想调select select也可以啊,里边只是有一些微小的区别而已。然后这个select,大家看里边要传一个什么东西呢?最简单的方式需要传一个。
21:01
Pattern select function好,这里面就又有了一个特殊的这样的一个函数类的定义,对吧?然后大家看到这是一个接口啊,Interface,然后它本身是一个方式,里边必须要实现的方法就叫做select,对吧?哎,那大家看到这个,那我们就重写这个方法就完了嘛,大家关键是要看一下里边的这个输入输出是什么,这个方法有点奇怪,它的输入叫做叫做pattern的一个一个map,为什么它是一个map呢?大家可能会想到,难道不应该是这个input这个类型吗?当前我们检测到的就是数据流里边的事件不都是这个吗?我们当前叫做那个login event对吧?都是这个事件嘛,那为什么它是包装成了一个map呢?然后这个map里边又是一个看key value对吧?K是一个string,然后value又是一个list类型的in,这是个什么东西呢?这其实就是前面我们讲的,不是要用一个模式去检测吗?那大家想我现在检测到的一组,检测到这个复杂事件,是不是一组事件呀?
22:06
对于我们这个例子来讲,是不是至少应该有第一次登录失败和第二次登录失败,是不是应该有两个事件啊?哎,所以这里边就涉及到这样一个问题啊,我把这个给大家看的明显一点,这是第一次登录失败,这是第二次登录失败啊,那所以这里边有一个问题,就是说你后边如果要是直接在这个select要把它提取出来的话,你看到的是不是我们提取出来都是一个log event呀,那你怎么区别谁是第一次登录失败,谁是第二次登录失败呢?所以在CP的底层,它是把我们匹配出来的那个事件保存在了一个map数据结构里面,然后这里边的key是什么呢?Key就是前边大家看这里边不是给了一个name吗?不是给了一个名称吗?所以我保存的时候它的key就叫first few,然后后面是不是跟了一个logging event这样一个事件啊?那检测到这个事件就是对应它的那个值对吧?然后那second second few,这是不是也是一个K,然后对应检测到的那个logging even的那个事件,就是它对应的那个值对吧?啊,那有同学可能想到,那为什么这里边还还是给它包装成了一个例子的呢?为什么还是一个列表呢?啊,那现在我们可能考虑不到那么多,那是因为这里边啊,每一个单独检测的事件,其实未必返回的只有一个事件。
23:26
有可能要返回很多个,那如果很多个的话,是不是这里边就应该是一个K,就表示一个list呀,啊,那现在我们只有一个啊检测我们想检测的只有一个事件,所以说这个大家不用考虑,就相当于是单元素的粒子的嘛。然后最后返回的结果是不是变成了一个out类型,这就是你自己定义了想要什么要什么,那大想是不是我检测到这两个登录失败事件,包装成一个warning输出就可以了。这是不是就是我们想要的结果啊啊,所以接下来我们就在代码里面做一个实现啊,Select这里边我就直接去拗一个我自定义当前这个叫做logging file啊,Match匹配的这个detect对吧,检测啊,然后warning啊做一个这个报警。
24:13
这是自定义的一个pattern select function,然后这里边最终我们得到的结果就直接可以叫做warning strip,当然了,这里得到这个类型其实也应该改成我们定义好的那个po类型,叫logging feel warning,对吧?呃,叫这个啊,报警报警的这个类型,最后把它打印输出就可以了,这就是我们这个CP的处理流程,然后接下来最后一步实现自定义的。呃,这个叫做pattern select function,所以这里面public static class,我把这个直接copy过来。它需要implement实现一个接口,当前这个接口就叫做pattern select function,大家看到它有一个in in有一个out,有两个类型对吧?其实大家发现了它是不是就跟mapp一样啊,对吧?只不过这里边比较特殊,就是因为我们是复杂事件处理,所以说这里边的输入不能你直接就输入一个input的类型,而是要给一个这个map类型对吧?检测到的这个是一个k value6的这样的一个一组事件啊啊,那所以这里边我们就input类型,Logging event对吧,事件类型,然后output类型是不是logging feel warning啊,报警类型对吧?这个一写上面就不报错了,接下来必须要实现的就是一个select方法,然后在这个里边,呃,其实大家就能想到,我当前就可以定义出来都是logging event啊,我就从里面获取,第一次登录失败,First few event,大家想应该怎么拿呢?
25:57
是不是直接就可以,这个叫做pattern对吧,我直接就在pattern里边,当前这是个map嘛,Map我是不是直接可以get呀,对吧,Get一个K,那我当前的K是不是就是first few,就是我们之前定义的这个name对不对,当前事件检测匹配的这个name啊,模式里边的这个name,所以我就get这个K,然后接下来注意得到的是一个list,对吧?哎,那当前的这个list呢,我们知道里边就只有一个元素,那我是不是直接GET0就可以了。
26:29
啊,当然你也可以把它当成那个迭代器类型,对吧,就是it.next这样去写,是不是也是一样啊,对吧,直接把当前这个事件拿到就可以了,那另外我还可以logging event second second film event,哎,那这个同样也是pattern get,当前这个应该是second film,然后哎,这个我也可以去GET0,也可以去next,对吧,直接拿出来就完事了,最后我们要返回的是要包装成一个想要的logging feel warning类型。
27:08
里面大家还记得首先要的是当前的那个idd的话,其实大家知道这个每一个event里面都有,对吧?而且我们既然K外了嘛,都都是一样的ID啊,所以这里边我直接随便拿一个吧,比方说first few event get u ID放在这,然后那就是第一次登录失败的时间戳,Get time Sam放在这儿,第二次登录就是最后一次,我们现在是第二次对吧?第二次登录失败的时间戳放在这儿,最后还有一个报警信息,Logging film,两次对吧?To times,哎,这就是我们。完整的这个处理流程,这就是CP的这个处理流程,好,那那接下来我们来运行一下,看看这个代码能不能正常运行。哦,首先大家要注意,我们现在的这个测试里边是加了这个success对应的这个成功的对吧?哎,那现在我们就要考虑一下了啊,就如果说加入了这个success,它能正常检测出来吗。
28:08
能够检测到吗?诶,大家看它检测到了。是不是4243连续两次登录失败检测到了对吧?4344连续两次登录失败也检测到,哎,所以这个是看起来没有问题的,哎,那有同学可能讲,那假如说这个按我们一开始的那个啊,四二两两个这个,呃,四二的这个登录成功,这个如果再运行还能检测到吗?大家看这个过程的话,其实是4344完全没有影响,但是四二我们觉得就应该会有影响,对吧?啊,那我们看一下当前它会检测到什么,诶大家看它检测到的就是4344,这是正常的,正常的连续两次登录失败,但是4243之间,是不是因为四二这本身这个时间就应该是在他之间的呀,所以他他检测这个是这个不属于我们要报警的这个信息,对吧。
29:03
所以这个是不是就完全没问题了啊,那当然大家也可以把这个删掉啊,我们最原始的这个状态,842843844,大家会想到这个肯定可以报警对吧,中间你插入乱序的那个登录成功的数据都可以报警,这个当然是没问题的了,肯定可以报警啊,这就是关于这个CP,那大家其实能够想到它底层的这个处理方式,其实就是有一个需要把我们之前所有的那个数据,假如说watermark没到的话,是不是之前所有的数据是应该缓存起来啊。等到watermark涨到这个时间点,他他才去处理之前的所有数据,对吧?所以这里边我们就会看到他总能够正确处理乱序数据,这就解决了我们之前所有的问题了啊啊,那当然有同学可能想到,那这个时候如果说我这是连续两次登录失败啊,那假如说连续三次登录失败,这个还能扩展吗?之前我们不是说那个逻辑很麻烦吗?诶大家想三次登录失败那也简单,那怎么办?
30:02
我这里边是不是直接再来一个这个next对吧,既然你前面是可以next second few,那这里边我是不是就可以在next来一个third few啊,对吧,那这个完全没问题嘛,那后面还是检测这个feel对吧?啊,当然了,这里面大家要注意啊,这个如果是二的话,这可能我们就检测不到,为什么呢?因为大家想它是按照那个窗口来开的,那是不是应该是。前闭后开啊对吧,应该还是这个,呃,就是这个时间戳是有一个前闭后开的关系的,所以你前面如果是两秒钟之内的话,当前我们这个数据,那是不是4243是包含在里边,四四是不是不应该包含在这个两秒窗口内啊啊所以这里边我们可以把这个扩大一点,比方说三秒钟之内连续三次登录失败啊,大家想这里边我就做一个这个就不叫这个second了啊,我叫last few对吧,然后下面我这个就用是不是用那个third few啊。接下来这个换成这个last film这个time,然后我再运行一下,大家看看现在的效果怎么样,现在是4243443次登录失败对吧。
31:13
我现在检测的这个过程当中啊,大家看那个就是定义了一个pattern,然后多了一步next,然后接下来我们这里取的时候是first和last last取的是third对吧?最后一次啊,大家看这是不是4244之间,然后哎,当然这个我们没改那个数据输出的这个结果,对吧,应该现在是不是应该三次了对吧,4244之间最后一次登录失败对吧?检测出来了。这就是这个CP啊,这个使用的这个过程,大家可以先感受一下,它这种使用方式,比我们之前那个process function就会方便很多。
我来说两句