Flink实战(一):订单支付实时监控

一、背景

​ 在电商平台中,最终创造收入和利润的是用户下单购买的环节;更具体一点,是用户真正完成支付动作的时候。用户下单的行为可以表明用户对商品的需求,但在现实中,并不是每次下单都会被用户立刻支付。当拖延一段时间后,用户支付的意愿会降低。所以为了让用户更有紧迫感从而提高支付转化率,同时也为了防范订单支付环节的安全风险,电商网站往往会对订单状态进行监控,设置一个失效时间(比如15分钟),如果下单后一段时间仍未支付,订单就会被取消。

​ 本文将使用FlinkCEP库来实现这个功能。

二、基本需求

​ 1.用户下单之后,应设置订单失效时间,以提高用户支付的意愿,并降低系统风险

​ 2.用户下单后15分钟未支付,则输出监控信息

三、解决思路

​ 利用 CEP 库进行事件流的模式匹配,并设定匹配的时间间隔。

四、具体实验步骤

我们简化数据为:用户ID(orderId Long),事件类型(eventType String),事件时间(eventTime Long)。

其中时间类型包括:create 和 pay

我们先将事件流按照订单号orderId分流,然后定义这样的一个事件模式:在15分钟内,事件“create”与“pay”非严格连续

1.创建maven工程

​ 可以叫做OrderTimeoutDetect。

2.配置pom文件

因为需要使用CEP库 所以要引入相关依赖

		<dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-cep_2.11</artifactId>
            <version>1.9.1</version>
        </dependency>

其他还有Flink通用的依赖

		<dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-java</artifactId>
            <version>1.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-streaming-java_2.11</artifactId>
            <version>1.9.1</version>
        </dependency>

编译打包方式官方推荐用maven-shade-plugin。完整pom链接

3.定义POJO

定义OrderEvent 完整类输入的订单事件流;另外定义OrderResult 完整类为输出显示的订单状态结果。

4.创建主类OrderTimeout

先创建流作业的环境已经简单的配置 使用的是事件时间

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.setParallelism(1);

测试用的自定义数据

DataStream<OrderEvent> dataSource = env.fromCollection(Arrays.asList(
                new OrderEvent(1L, "create", 1558430842L),
                new OrderEvent(2L, "create", 1558430843L),
                new OrderEvent(2L, "pay", 1558430844L)
        ))

有了数据源之后,我们需要对数据流按照orderId做keyby分流

KeyedStream<OrderEvent, Long> orderEventStream = dataSource.assignTimzestampsAndWatermarks(new AscendingTimestampExtractor<OrderEvent>() {
            @Override
            public long extractAscendingTimestamp(OrderEvent element) {
                return element.getEventTime() * 1000;
            }
        })
                .keyBy(new KeySelector<OrderEvent, Long>() {
                    @Override
                    public Long getKey(OrderEvent value) throws Exception {
                        return value.getOrderId();
                    }
                });

在做keyBy之前日常加上waterMark。因为我们这里的时间的顺序的 所以用assignTimzestampsAndWatermarks就行,生产中很少用。

这样就得到了一个KeyedStream,留着备用。

5.定义Pattern 匹配模式
Pattern<OrderEvent, OrderEvent> OrderPayPattern = Pattern.<OrderEvent>begin("begin").where(new SimpleCondition<OrderEvent>() {
            @Override
            public boolean filter(OrderEvent value) throws Exception {
                return value.getEventType().equals("create");
            }
        })
        //非严格连续 
        .followedBy("follow").where(new SimpleCondition<OrderEvent>() {
            @Override
            public boolean filter(OrderEvent value) throws Exception {
                return value.getEventType().equals("pay");
            }
        })
    //设定超时时间
    .within(Time.seconds(15));
6.定义超时支付的输出标签,用标签sideOutput
        OutputTag<OrderResult> orderTimeoutOutput = new OutputTag<OrderResult>("orderTimeout"){};

特别注意:不是简单的new 一个类,是一个匿名内部类

7.将keyBy后的流绑定模式 keyedStream转换成patternStream
PatternStream<OrderEvent> patternStream = CEP.pattern(orderEventStream, OrderPayPattern);
8.从patternStream中获取匹配的流(包括超时的和正常的 等等要分别处理)
DataStream<OrderResult> completedDataStream = patternStream.select(
   //第一个参数 刚定义的超时输出的标签 
   orderTimeoutOutput, 
   //第二个参数 处理超时的流
   new PatternTimeoutFunction<OrderEvent, OrderResult>() {
                @Override
                public OrderResult timeout(Map<String, List<OrderEvent>> pattern, long timeoutTimestamp) throws Exception {
                    Long timeoutOrderId = pattern.getOrDefault("begin", null).iterator().next().getOrderId();
                    return new OrderResult(timeoutOrderId, "timeout");
                }
            },
     //第三个参数 处理正常的流
     new PatternSelectFunction<OrderEvent, OrderResult>() {
                @Override
                public OrderResult select(Map<String, List<OrderEvent>> pattern) throws Exception {
                    Long payOrderId = pattern.getOrDefault("follow", null).iterator().next().getOrderId();
                    return new OrderResult(payOrderId, "success");
                }
            });
9.将获取到的completedDataStream中流分别输出
//正常支付
completedDataStream.print();
//超时支付
DataStream<OrderResult> sideOutput = ((SingleOutputStreamOperator<OrderResult>) completedDataStream).getSideOutput(orderTimeoutOutput);sideOutput.print();
10.最后别忘了
env.execute("order timeout job");

完整的代码链接

https://github.com/comsir/Flink-UserBehaviorAnalysis/tree/master/OrderTimeoutDetect

你可能感兴趣的:(大数据,Flink)