00:00
前面我们讲到了cep里边,呃,个体模式里边的条件和量词,对吧?然后接下来呢,再给大家详细的说一说模式序列,那么也就是所谓的组合模式,组合模式里边最简单最经典的定义,其实就是要区分不同的所谓近邻,那大家看一看上下体表现出来的这两种情况一样吗?大家说。因为我们说这个。这个不同的模式,这个简单模式组合在一起的时候,其实就相当于大家发现一个简单模式,相当于就是按照条件去筛取一个简单事件,对不对,然后不同的简单模式组合在一起,就相当于是代表了他们之间的相互谁前谁后这样的关联,对吧?呃,所以正常来讲,一个模式序列里边,主要我们关心的就是谁前谁后,谁先发生,谁在后边。那这里边就有一个所谓的近邻关系了,我们往往是要选择哎,谁在前面,谁在后边,他们是近邻发生的这样的一个状态,那这里边呢,又分两类,一类是上边大家看到的正方形和圆圈这样的关系。
01:17
他们俩的关系是不是一个正方形后面一定要紧跟着一个圆圈啊?哎,这样的状态,这是不是在选择的过程当中,中间就不能有别的支线插进来,对吧,必须得是他俩紧跟在一起,而下边这种情况呢,它就相对来讲是不是宽松一些。可以是,只要是方框在五角星前边就可以了,至于中间,哎,中间有没有或者说隔了几个是不是并不关心啊,只要他俩符合一前以后的关系就可以,所以这就是所谓的两种不同的竞邻模式,一种叫严格竞邻,另外一种啊,一般叫宽松竞灵,对吧?所以针对这两种不同的净邻模式,我们往往就可以在。
02:03
模式序列里边定义出简单模式,它们之间的组合关系啊,那一般我们用什么样的方法去组合起来呢?我们一个一个来看啊,首先是严格禁邻,严格精灵,简单的来说就是一个接着一个,中间没有别的插入。我们调用的时候用点next来制定啊,大家知道这个英文单词里边next的意思就是对,就是下一个嘛,是不是就一定要紧邻着你才能说下一个对不对啊,你如果要中间隔着的话,那就不叫下一个了,所以大家从字面上也能够理解清楚。大家看一个例子吧,如果一个模式我们前面是后面是BA,然后点next b的话,如果定义了这样一个模式,那现在来了一个序列啊,这个B1B2是代表就是都是符合B这样条件的这样的事件,对不对?不同的事件都符合B这个条件,那么大家看来了一个ACB1B2,那么我们这个模式有符合它的吗?没有,我们要求是不是A和B必须要对严格禁令,所以中间插了个C,那就不行了。好,与之相对应的是有一个宽松禁邻,宽松禁邻的话,那就是中间是不是可以出现别的东西啊,只要一前一后就可以了,所以它的定义就是。
03:25
Followed by,字面上理解什么叫followed by,就是跟在后边的对吧?呃,那跟在后边那就有可能还有别的呀,呃,只要是你排在后边那就都算,所以大家看一下这个例子啊,如果是a followed by b的话,那么ACB1 B2有没有匹配?哦,有匹配,匹配出来就是。哎,C算不算不算,算不算,大家注意啊,C是不是并不符合我们这里面定义的那个简单模式的那个定义啊,这里边的一个简单模式是要符合A的这个条件,一个是要符合B对吧,那这里边我们是不是筛出来一定是一个A一个B这样的一个组合啊,只不过他们之间可以插进来别的别的不管,只只看它们把它们筛出来,所以这里边我们筛出来就应该是。
04:18
A,对,这个是符合a followed by b这样的一个模式定义的。啊,那有同学可能会想到,那后面还有个B2呢,那就匹配不到了吗。呃,在这个followed by里边确实是它就匹配不到了,因为他是不是已经用在跟B1匹配上了呀,已经检测出这个模式之后,呃,它就不再保留它的这个状态了,那什么情况下可以把A和B2这个匹配也匹配出来呢?下面再给大家介绍一个所谓的非确定性宽松禁令。那所以前面宽松进行,前面又加了个非确定性,是不是相当于进一步把条件放宽了,那这个表述是followed by any。
05:01
字面上理解就是。啊,字面字面上理解就是在后面就行,而且是呃,前面你用过的也可以,对吧,就是直接跟在谁后面都行安嘛,所以这里边如果要是a followed by an b的话,我们对于这样一个ACB1 B2的序列匹配出来的结果就是AB1AB2都可以提取出来。这就是一些比较常见的模式序列,我们往往就是按照这种方式去定义的。呃,除了这个前面讲到的这些模式序列之外呢,还可以有一些其他的定义方法,比方说我们可以定义前面定义的都是谁紧跟在谁后边对吧,或者是谁啊,Followed by跟在他后边,不需要紧邻,都是说确定性正面的这种肯定的关系,那假如说我们想定义的是说我不希望谁跟在谁后面。就是要他俩得得分开的那种状态才行,对不对?呃,如果我要想找这种情况,怎么找呢?这里大家看到啊弗link cp里边也提供了两种这样的判断方式,一个叫not nextx not nextx,意思就是说是对后边这个事件是不是不要严格紧邻前一个事件发生啊,对吧,只要它不是严格紧邻的发生就可以匹配的上,那与之对应就还有一个not followed by,对吧?这里大家要注意一下,这个not follow by表示什么意思呢?它不是说一个事件就不在另外一个事件的后边,直接就就是那那大家会想你假如说我字面含义就是说在后边不出现某个事件。
06:42
那我怎么知道他后面永远不出现,大家想想是不是这样,比方说我A后面not followed by b,那是不是意思就是说来了一个A检测到了对吧,这个匹配上了,然后我不想让它后面出现B的话,Not follow by b,那你说什么时候才是个头呢?什么时候才叫匹配上这个模式了呢?
07:02
因为我们的事件流是无穷无尽的,那你如果这么去定义的话,那就永远检测不到它的匹配,我前面的AA的那个状态是不是一直得保持着呀?这显然不是一个合理的方式。所以not followed by,一般它是用在什么情况下呢?它是用在两个事件之间,对吧?就它不要直间,最后我们结尾就是一个note for,这就肯定不行了,它是在两个事件之间,表示的是某个事件,不要在这两个事件之间去发生。啊,这样的一个意思,好,所以这里大家注意一下几个要点啊,首先前面讲到的所有的模式序列,我们在匹配的过程当中,第一个。这个模式简单模式必须是begin对吧,必须以begin开始,然后接下来的这种连接方式呢。最后末尾不能以note followed by结束,因为这个就永远检测不到了嘛,无穷无尽的这个事件你要去一直保存着状态。另外,Note类型的模式不能被optional所修饰。
08:07
大家想想这是为什么呢?Optional指的是可有可无,对吧?你已经要求他不出现了,你还可有可无,那那言下之意是不是所有的你你你都要啊,是吧,我全都要,是不是啊?所以这种情况是不允许的,Not类型的模式是不能被optional所修饰的。另外大家注意一下啊,还有一个就是大家看前面提到的这些呢,都是事件互相之间的这种关系,这里边是不是没有提到我们所说的,比方说哎,前面提到的就是两秒钟之内这个连续登录失败几次对吧?呃,这个时间是不是没有涉及到这个概念啊,CP里边其实也给我们提供了一个跟时间相关的特点,相关的语义,什么样的特点呢?就是什么样的一个方式呢?就是设定时间约束,比方说我可以next.with。
09:04
Within,然后跟一个T,这就表示什么。是不是就是前面我要匹配的整个的这个模式,必须在对这个十秒,就比方说这里边是十秒钟,那就必须在十秒钟之内匹配上这些东西才是有效的,如果要是超过十秒钟,是不是相当于就超时就无效了呀?啊,所以这是这个弗林克里边就相当于把事件和时间通通的管理起来,通通的都能让我们去做这种复杂的判断了。好,然后呃,那具体的检测过程当中,大家看这个代码里边呢,就是这样的三步,整体来讲就是我先有一个input,这是一个data stream,对吧,然后接下来又会有一个pattern定义前面的一个模式序列,接下来是不是就可以把这个pattern应用到data stream上,就得到了一个,大家看得到了一个新的数据类型叫做。
10:04
Pattern stream又是一个新的数据类型了啊,所以得到这个pattern stream之后,那又怎么办呢?大家一定还记得我们之前讲过,各种各样的一个成兑出现的操作,其实都是以围绕着data stream展开做文章的,对吧?就是通过data stream做一个操作,变成了一个比方说变成了k stream,变成了一个window stream之后,是不是做了一系列操作之后又回到了data stream,然后又可以输出了,对吧?啊,往往都是这样的一些流程,那这里同样也不例外,这里是应用了pattern之后得到了pattern stream接下来怎么在。得到我们想要的那些事件,一组一组的那个事件序列,再把它提出来,提出提出来形成一个这个data stream呢,后面要应用的就是一个select的方法,或者是一个select select方法就可以从检测到的事件序列里边把想要的事件提取出来啊,那当然了,它里边要传一个参数了,这个参数一般情况可以去实现一个什么呢?实现一个select的方式可以自定义一个一个函数,也可以去实现,就是一个select function这样函数类的接口,对吧?
11:21
这里大家注意一下啊,它是用什么东西来接收匹配到事件序列的呢?数据结构是一个是一个map类型。那大家看这个map它的T是什么类型。是一个string类型,那value呢?Value是in,是我们的那个输入类数据类型,对不对,In类型的。一个可迭代的类型对不对,那所以最后我们检测到的输入事件是不是都在这里面保存着呀,那前面的这个string又是什么呢。大家还记得我们前面在定义模式的时候,点begin,是不是后面要给一个比方说,哎,对,一个字符串begin,对吧,点next,一个字符串middle,那那个字符串是不是就代表了当前简单模式的名称或者说键值啊,所以这里边我们的这个剑,这个string啊,其实就是当时定义好的那个名称。
12:21
所以大家看一下我们怎么样去拿到匹配到那个事件,那个那一组事件的复杂事件呢?很简单,就是pattern,这是这个map,我们可以直接get,比方说我们知道第一个事件,假如叫start。那个模式叫start对吧,我就直接get start,那拿到的东西是不是就应该是一个一个可迭代的类型啊啊,然后我可以用这个迭代器的方法,或者用get方法就可以得到里边的值。那么start这里面得到的那个值应该是什么呢?应该就是我们一开始定义的符合start简单模式定义好的那个事件,提取出来的那一个事件就保存在这里了。
13:05
那同样如果我们要后面有middle有and的话,是不是也可以根据一开始我们那个定义好的那个名称,把对应匹配到的那个事件提取出来啊,啊,所以这些东西都是可以在这里去做操作。那大家看最后还可以干什么呢?呃,Out对吧?呃,直接输出一个out类型就可以得到我们最后要的data stream,还是包装成一个data stream输出了。这就是整个的这个过程,就是从一开始定义模式到应用的模式,生成一个p stream,最后再从stream里边。按照这个我们的模式提取出对应的那个事件序列,复杂事件,然后就可以转换成data stream继续做处理了。另外还有一个,还有一个提到的,因为我们前面讲到在CP里边也提供了跟时间相关的处理方法,有一个叫做within的东西,对吧?哎,那之前跟大家讲到这个,如果要是说我们定义了一个WITHIN10秒的话,那是在十秒钟之内,前面已经符合的那些事件匹配得到的这个就是不是正常,我们select就select出来了。
14:13
那大家会想到有时候我是既要快又要最后保持这个正确性的啊,这又是我们之前的那个需求对吧,要平衡这两方面呢,那前面我可能我我不能等太久,所以我这个VZ就是很短时间内对吧,给了一个很短的时间,那假如说。真正超时的那些事件呢,我不想直接丢掉,我还想把它做一些别的处理呢。CP里边给我们提供了这样超时事件提取的方法,所以大家看超时的事件,它并没有直接丢掉,而是相当于。类似的给我们放在了另一条流里边,对不对,我们通过其他的方法能把它抽取出来,怎么样去抽取呢?哦,大家看啊,这里边其实就是用一个output tag。
15:03
来定义一个超时的时间序列,然后我们可以定义,大家看这个这个过程提取的时候是什么select要再传一个output type。要把这个定义好的测试物流的标签要传进去,然后接下来传这个select方式的时候,传函数的时候就不止传一个了。要传俩,所以大家看到前面第一个函数是处理超时事件的一个函数。Comeout event对吧?而后边这个就是我们正常的select的那个方式对吧?处理正常完成的匹配到的事件流的那个函数,我们把这两个分别实现传进去之后,怎么拿到这个超时事件这个流里边的东西呢?用测输出流的方式,你不是定义了那个output tag吗?这里边我们在用这个得到的data stream result去get output。
16:00
根据这个标签把它提出来,就可以处理这个超时那部分的事件序列了。所以大家看这一个是不是底层已经能够想到它是用什么实现的。其实就是测输出流对不对,把超时的那部分事件全放到一个测输出流里边去了,所以我们后边可以用get set output把它再拿出来啊,这就是这个cep里边所有能够处理的事情,其实已经跟大家做了一个比较完整的介绍。
我来说两句