Flink处理函数

本文详细介绍了Flink的处理函数,包括ProcessFunction、KeyedProcessFunction等,强调其在时间戳、水位线、定时器等方面的灵活性,并提供了一个统计最近10秒内最热门URL的案例,演示了如何结合窗口和增量聚合实现Top N问题,以及在全窗口和按键分区窗口中遇到的问题和解决方案。
摘要由CSDN通过智能技术生成
  • 处理函数的功能和使用
    之前学习的转换算子,一般只是针对某种具体操作来而言,能够拿到的信息比较有 限。比如 map 算子,只能获取到当前的数据, 定义它转换之后 式;而像窗口聚合这样的复杂操作, 还可以获取到当前的状态(以累加器 Accumulator 形式出现)。另外还有富函数类,比如RichMapFunction 供了获取运行时上下文的方法 getRuntimeContext(),可以拿到状态,还有并行度、任务名 称之类的运行时信息。但是无论那种算子, 如果我们想要访问事件的时间戳, 或者当前的水位线信息, 都是做不到的。在定义生成规则之后,水位线会源源不断地产生, 像数据一样在任务间流动,我能像数据一样去处理它; 跟时间相关的操作, 目前我们只会用窗口来处理。而在有些应需求中,要求我们对时间有更精细的控制,需要能够获取水位线,甚至要把控时间, 这就不是基本的时间窗口能够实现的了。

    处理函数提供了一个“定时服务” (TimerService), 可以通过它访问流中的事件(event)、 时间戳(timestamp)、水位线  (watermark),甚至可以注册定时事件。而且处理函数继承了 AbstractRichFunction 抽象类,  所以拥有富函数类的所有特性, 同样可以访问状态(state) 和其他运行时信息。此外, 处理函 数还可以直接将数据输出到侧输出流(side output) 中。所以, 处理函数是最为灵活的处理,可以实现各种自定义的业务逻辑;同时也是整个 DataStream API 的底层基础。

    处理函数的使用与基本的转换操作类似, 只需要直接基于 DataStream 调用.process()方法传入一个 ProcessFunction 作为参数就可以了。
    用示例:

    package com.company.flink.demo;
    
    import com.company.flink.data.ClickSource;
    import com.company.flink.entity.Event;
    import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
    import org.apache.flink.api.common.eventtime.WatermarkStrategy;
    import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
    import org.apache.flink.streaming.api.functions.ProcessFunction;
    import org.apache.flink.util.Collector;
    
    import java.time.Duration;
    
    public class ProcessFunctionDemo {
        public static void main(String[] args) throws Exception {
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
            env.addSource(new ClickSource())
                .assignTimestampsAndWatermarks(
                        WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO)
                                .withTimestampAssigner((SerializableTimestampAssigner<Event>) (event, l) -> event.timestamp)
                ).process(new ProcessFunction<Event, String>() {
                    @Override
                    public void processElement(Event value, Context ctx, Collector<String> out) {
                        if (value.user.equals("zhangsan")) {
                            out.collect("name = " + value.user + ", url = " + value.url);
                            out.collect("name = " + value.user + ", url = " + value.url);
                        } else if (value.user.equals("lisi")) {
                            out.collect("name = " + value.user + ", url = " + value.url);
                        }
                        //getRuntimeContext(); //获取运行时上下文
                        //ctx.timerService().currentWatermark() 获取水位线
                    }
    
                    //定时器
                    /*@Override
                    public void onTimer(long timestamp, ProcessFunction<Event, String>.OnTimerContext ctx, Collector<String> out) throws Exception {
                        super.onTimer(timestamp, ctx, out);
                    }*/
    
                    })
                .print();
    
            env.execute();
        }
    }

    1)  processElement():
    用于“处理元素”,定义处理的核心逻辑。这个方法对于流中的每个元素都会调用一次。

    2)onTimer():
    用于定义定时触发的操作。这个方法只有在注册好的定时器触发的时候才会调用,定时器是通过“定时服务”TimerService 来注册的。打个 比方, 注定时器(timer) 就是设了一个闹钟, 到了设定时间就会调用 onTimer()。所以它本质是基于时间的“回调”方法,在事件时间语义下就由水位线(watermark) 来触发了。
    需要注意的是,onTimer()方法只是定时器触发时的操作,而定时器(timer) 真正的设置需要用到上下文 ctx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值