Flink CEP笔记

本文详细介绍了Flink中的复杂事件处理库CEP,包括CEP的基本概念、量词的使用、条件设置、模式序列定义以及注意事项。通过实例解析了如何在事件流中检测模式,如使用times、optional、greedy等操作符,以及where、or、until条件。同时,文章还讲解了事件的提取方法,包括匹配事件和超时事件的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是 CEP

  • CEP 是 Complex Event Processing 的缩写,意为"复杂事件处理";
  • Flink CEP 是 Flink 中实现的复杂事件处理库;
  • CEP 允许在无休止的事件流中检测事件模式,让我们有机会掌握数据中的重要部分;
  • 一个或多个由简单事件构成的事件流通过一定的匹配规则,然后输出用户想要得到的数据;

二、量词 Quantifier

  • start.times(6):匹配出现 6 次;
  • start.times(6).optional:匹配出现 0 次或 6 次;
  • start.times(3,6):匹配出现 3 ~ 6 次;
  • start.times(3,6).greedy:匹配出现 3 ~ 6 次,并且尽可能多的匹配;
  • start.oneOrMore():匹配 1 次或多次;
  • start.timesOrMore(2).optional.greedy:匹配 0 次或 2 次或多次,且尽可能多的重复匹配

三、条件:where、or、until

  • 简单条件:start.where(event => event.getName.startsWith("Liu"));
  • 组合条件:pattern.where(event => ...).or(event => ...); pattern.where(e => ...).where(e => ...);
  • 终止条件:如果使用了:oneOrMore 或者 oneOrMore.optional ,建议使用 .until 作为终止条件,清理状态;
  • 迭代条件:能够对模式之前所有接收的事件进行处理,调用 .where((value,ctx) => {...}),可以调用 ctx.getEventsForPattern("name")

四、模式序列

  • 严格近邻:紧挨着下一个发生的事件,由 .next() 指定,例如:对于事件 "a next b",序列 [a,c,b1,b2] 没有匹配;
  • 宽松近邻:两个事件不必紧挨着,中间可以有不匹配事件,由 .followedBy() 指定,例如:对于事件 "a followedBy b",序列 [a,c,b1,b2] 匹配为 {a,b1};
  • 非确定性宽松近邻:进一步放宽条件,之前已经匹配过的事件也可以再次使用,由 .followedByAny() 指定,例如:对于事件 "a followedByAny b" ,序列 [a,c,b1,b2] 匹配为 {a,b1},{a,b2}
  • notNext():不想让某个事件紧邻前一个事件发生
  • notFollowedBy():不想让某个事件在两个事件之间发生

五、注意事项

  • 所有模式序列必须以 .begin() 开始;
  • 模式序列不能以 notFollowedBy() 结束;
  • "not" 类型的模式不能用 optional 修饰;
  • 此外,还可以为模式指定时间约束:next().within(Time.seconds(6)) ,6 秒之内的事件

六、事件的提取

1.匹配事件的提取

...
...

//定义匹配模式
val pattern = Pattern.begin[LoginLog]("begin").where(_.loginType == "fail")
      .next("next").where(_.loginType == "fail")
      .within(Time.seconds(2))

//CEP将匹配模式代入数据流,得到匹配好的数据
val patternStream = CEP.pattern(sourceData, pattern)

val loginFailData: DataStream[LoginFailView] = patternStream.select(new LogFailSelectFunciton())

...
...

class LogFailSelectFunciton() extends PatternSelectFunction[LoginLog, LoginFailView] {
  override def select(map: util.Map[String, util.List[LoginLog]]): LoginFailView = {
    val begin = map.get("begin").iterator().next()
    val next = map.get("next").iterator().next()
    LoginFailView(begin.userId, "搞事情!!!")
  }
}

        select 的参数:Map[String, util.List[LoginLog]]  ,其中 key (String) 就是每个模式的名称,value 就是接收到事件的 Iterable 类型

2.超时事件的获取

       当一个模式通过 within() 方法指定了窗口检测时间时,部分事件序列可能因为超过窗口长度而无法被丢弃,为了能够处理这些超时的部分匹配,select 和 flatSelect API 调用允许指定超时处理程序;

超时处理程序会接收到目前为止由模式匹配到的所有事件,由 OutputTag 定义接收到的超时事件序列。

例:实时监控订单超时,15分钟之内未支付则视为超时

...
...

val pattern = Pattern.begin[OrderLog]("begin")
      .where(_.orderType == "create")
      .followedBy("follow")
      .where(_.orderType == "pay")
      .within(Time.minutes(15))

val patternDataStream = CEP.pattern(resourceData, pattern)

val outputTag = new OutputTag[OrderResult]("order-timeout")

val orderResultDataStream = patternDataStream.select(outputTag,
      new OrderTimeoutFunction(),
      new OrderPatternFunction())

orderResultDataStream.getSideOutput(outputTag).print("timeout")
orderResultDataStream.print("pay")

...
...

class OrderTimeoutFunction() extends PatternTimeoutFunction[OrderLog, OrderResult] {
  override def timeout(map: util.Map[String, util.List[OrderLog]], l: Long): OrderResult = {
    val begin = map.get("begin").iterator().next()
    OrderResult(begin.orderId, "已超时!!!")
  }
}

class OrderPatternFunction() extends PatternSelectFunction[OrderLog, OrderResult] {
  override def select(map: util.Map[String, util.List[OrderLog]]): OrderResult = {
    val begin = map.get("begin").iterator().next()
    val end = map.get("follow").iterator().next()
    OrderResult(begin.orderId, end.orderType)
  }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值