Flink(九)CEP

本文详细介绍了Flink的复杂事件处理库CEP,包括CEP的基本概念、快速入门示例、模式API的使用,如个体模式、组合模式、匹配后跳过策略等,并展示了如何处理匹配事件和超时事件,阐述了CEP在实时流数据分析中的应用和重要性。
该文章已生成可运行项目,

1.概述

所谓 CEP,其实就是“复杂事件处理(Complex Event Processing)”的缩写;而 Flink CEP,就是 Flink 实现的一个用于复杂事件处理的库(library)。那到底什么是“复杂事件处理”呢?就是可以在事件流里,检测到特定的事件组合并进行处理,比如说“连续登录失败”,或者“订单支付超时”等等

具体的处理过程是,把事件流中的一个个简单事件,通过一定的规则匹配组合起来,这就是“复杂事件”;然后基于这些满足规则的一组组复杂事件进行转换处理,得到想要的结果进行输出

总结起来,复杂事件处理(CEP)的流程可以分成三个步骤:
(1)定义一个匹配规则,匹配规则就是模式,主要由两部分组成,每个简单事件的特征 和 简单事件之间的组合关系
(2)将匹配规则应用到事件流上,检测满足规则的复杂事件
(3)对检测到的复杂事件进行处理,得到结果进行输出

在这里插入图片描述

CEP 主要用于实时流数据的分析处理。CEP 可以帮助在复杂的、看似不相关的事件流中找出那些有意义的事件组合,进而可以接近实时地进行分析判断、输出通知信息或报警。这在企业项目的风控管理、用户画像和运维监控中,都有非常重要的应用

  • 风险控制
    当一个用户行为符合了异常行为模式,比如短时间内频繁登录并失败、大量下单却不支付(刷单),就可以向用户发送通知信息,或是进行报警提示、由人工进一步判定用户是否有违规操作的嫌疑。这样就可以有效地控制用户个人和平台的风险

  • 用户画像
    利用 CEP 可以用预先定义好的规则,对用户的行为轨迹进行实时跟踪,从而检测出具有特定行为习惯的一些用户,做出相应的用户画像。基于用户画像可以进行精准营销,即对行为匹配预定义规则的用户实时发送相应的营销推广;这与目前很多企业所做的精准推荐原理是一样的

  • 运维监控
    对于企业服务的运维管理,可以利用 CEP 灵活配置多指标、多依赖来实现更复杂的监控模式
    CEP 的应用场景非常丰富。很多大数据框架,如 Spark、Samza、Beam 等都提供了不同的CEP 解决方案,但没有专门的库(library)。而 Flink 提供了专门的 CEP 库用于复杂事件处理,可以说是目前 CEP 的最佳解决方案

2.快速入门

需要引入的依赖

<dependency>
 <groupId>org.apache.flink</groupId>
 <artifactId>flink-cep_${scala.binary.version}</artifactId>
 <version>${flink.version}</version>
</dependency>

接下来我们考虑一个具体的需求:检测用户行为,如果连续三次登录失败,就输出报警信息。很显然,这是一个复杂事件的检测处理,我们可以使用 Flink CEP 来实现。我们首先定义数据的类型。这里的用户行为不再是之前的访问事件 Event 了,所以应该单独定义一个登录事件 POJO 类。具体实现如下:

public class LoginEvent {
   
   
    // 用户id
    public String userId;
    // 用户ip地址
    public String ipAddress;
    // 用户登录成功与否
    public Boolean eventType;
    // 登录时间戳
    public Long timestamp;

  
    public LoginEvent() {
   
   }
    // 省略toString 有参构造
  
}
public class LoginDetectExample {
   
   
    public static void main(String[] args) throws Exception {
   
   
        // 创建一个表执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);

        env.setParallelism(1);
        env.getConfig().setAutoWatermarkInterval(100); // 100毫秒生成一次水位线
        // 1.用户登录事件
        SingleOutputStreamOperator<LoginEvent> streamOperator = env.fromElements(
                new LoginEvent("1", "192.168.10.1", false, 1000L),
                new LoginEvent("2", "192.168.10.6", true, 2000L),
                new LoginEvent("1", "192.168.10.1", false, 5000L),
                new LoginEvent("2", "192.168.10.6", false, 5000L),
                new LoginEvent("1", "192.168.10.1", false, 4000L)
        ).assignTimestampsAndWatermarks(WatermarkStrategy
                .<LoginEvent>forBoundedOutOfOrderness(Duration.ofSeconds(2)) // 延迟2秒保证数据正确
                .withTimestampAssigner(new SerializableTimestampAssigner<LoginEvent>() {
   
   
                    @Override // 时间戳的提取器
                    public long extractTimestamp(LoginEvent event, long l) {
   
   
                        return event.timestamp;
                    }
                })
        );

        // 2.定义模式
        // 2.1 模式的第一个事件是用户登陆失败
        Pattern<LoginEvent, LoginEvent> loginEventPattern = Pattern.<LoginEvent>begin("first-false")
                .where(new SimpleCondition<LoginEvent>() {
   
   
                    @Override
                    public boolean filter(LoginEvent loginEvent) throws Exception {
   
   
                        return !loginEvent.eventType; // 类型为false的则代表登陆失败
                    }
                })  // next衔接模式的第二个事件
                .next("second-false")
                .where(new SimpleCondition<LoginEvent>() {
   
   
                    @Override
                    public boolean filter(LoginEvent loginEvent) throws Exception {
   
   
                        return !loginEvent.eventType;
                    }
                }) // 以后的每个事件都用next衔接即可
                .next("third-false")
                .where(new SimpleCondition<LoginEvent>() {
   
   
                    @Override
                    public boolean filter(LoginEvent loginEvent) throws Exception {
   
   
                        return !loginEvent.eventType;
                    }
                });

        // 3.将模式应用到数据流,检测复杂事件
        PatternStream<LoginEvent> patternStream = CEP.pattern(streamOperator.keyBy(event -> event.userId), loginEventPattern);


        // 4.提取复杂事件,进行处理  select类似于map 只不过我们处理的是一组事件
        SingleOutputStreamOperator<String> warningOut = patternStream.select(new PatternSelectFunction<LoginEvent, String>() {
   
   
            @Override // 这里是一个map map的key就是我们定义的事件名称,value对应的事件列表,我们这里列表里只有一个事件,为什么是列表,因为我们定义的一个事件,它可能会重复发生
            public String select(Map<String, List<LoginEvent>> map) throws Exception {
   
   
                // 提取三次事件
                LoginEvent firstFailEvent = map.get("first-false").get(0);
                LoginEvent secondFailEvent = map.get(
本文章已经生成可运行项目
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jumanji_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值