Flink---处理函数

目录

前言

一、基本处理函数

        1.1处理函数的功能和使用

                1.1.1功能

                1.1.2 使用

        1.2 ProcessFunction解析

                1.2.1抽象方法 .processElement()

                1.2.2非抽象方法 .onTimer()     

                1.2.3处理函数的分类

                      (1)ProcessFunction

                      (2)KeyedProcessFunction

                      (3)ProcessWindowFunction

                      (4)ProcessAllWindowFunction

                      (5)CoProcessFunction

                      (6)ProcessJoinFunction

                      (7)BroadcastProcessFunction

                      (8)KeyedBroadcastProcessFunction

二、按键分区处理函数

        2.1定时器(Timer)和定时服务(TimerService)

        2.2 KeyedProcessFunction

三、窗口处理函数


前言

        无论是基本的转换、聚合,还是更为复杂的窗口操作,其实就是基于DataStream进行转换的,所以可以统称为DataStream API。

        在Flink更底层,我们可以不定义任何具体的算子(比如map,filter或window),而只是提炼出一个统一的“处理”(process)操作------它是所有转换算子的一个概括性的表达,可以自定义处理逻辑,所以这一层接口就被叫作“处理函数”(process function)

        

一、基本处理函数

        1.1处理函数的功能和使用

                1.1.1功能

                在很多应用需求中,要求我们对时间有更精细的控制,需要能够获取水位线,甚至要“把控时间”、定义什么时候做什么事,这就不是基本的时间窗口能够实现的了。这时就需要使用底层的处理函数。

                处理函数提供了一个“定时服务”(TimerService),我们可以通过它访问流中的事件(event)、时间戳(timestamp)、水位线(watermark),甚至可以注册“定时事件”。而且处理函数继承了AbstractRichFunction抽象类,所以拥有富有函数类的所有特征,同时可以访问状态(state)和其他运行时的信息。

                1.1.2 使用

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

stream.process(new MyProcessFunction())

        1.2 ProcessFunction解析

public abstract class ProcessFunction<I, O> extends AbstractRichFunction {

    ...
    public abstract void processElement(I value, Context ctx, Collector<O> out) throws Exception;

    public void onTimer(long timestamp, OnTimerContext ctx, Collector<O> out) throws Exception {}
    ...

}

        在源码中我们可以看到,抽象类ProcessFunction继承了AbstractRichFunction,有两个泛型类型参数:I表示Input,也就是输入的数据类型O表示Output,也就是处理完成之后输出的数据类型

        内部单独定义了两个方法:一个是必须要实现的抽象方法.processElement();另一个是非抽象方法.onTimer()。

                1.2.1抽象方法 .processElement()

                用于“处理元素”,定义了处理的核心逻辑。这个方法对于流中的每个元素都会调用一次,参数包括三个:输入数据值value,上下文ctx,以及“收集器”(Collector)out。方法没有返回值,处理之后的输出数据是通过收集器out来定义的。

  • value:当前流中的输入元素,也就是正在处理的数据,类型与流中数据类型一致。
  • ctx:类型是ProcessFunction中定义的内部抽象类Context,表示当前运行的上下文,可以获取到当前的时间戳,并提供了用于查询时间和注册定时器的“定时服务”(TimerService),以及可以将数据发送到“侧输出流”(side output)的方法.output()
  • out:“收集器”(类型为Collector),用于返回输出数据。使用方式与flatMap算子中的收集器完全一样,直接调用out.collect()方法就可以向下游发出一个数据。这个方法可以多次调用,也可以不调用。

             通过几个参数的分析不难发现,ProcessFunction可以轻松实现flatMap、map、filter这样的基本转换功能;而通过富函数提供的获取上下文方法.getRuntimeContext(),也可以自定义状态(state)进行处理,这也就能实现聚合操作的功能了。 

java:

public class ProcessExample {  
    public static void main(String[] args) throws Exception {  
        // 设置执行环境  
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();  
  
        // 创建数据源  
        DataStream<Tuple2<String, Integer>> dataStream = env.fromElements(  
                new Tuple2<>("Alice", 1),  
                new Tuple2<>("Bob", 2),  
                new Tuple2<>("Alice", 3)  
        );  
  
        // 应用 processElement 函数  
        DataStream<String> result = dataStream.process(new ProcessFunction<Tuple2<String, Integer>, String>() {  
            @Override  
            public void processElement(Tuple2<String, Integer> value, ReadOnlyContext ctx, Collector<String> out) throws Exception {  
                // 处理每个元素,这里只是简单地将元素的值转换为字符串并输出  
                out.collect(value.f0 + ": " + value.f1);  
            }  
        });  
  
        // 打印结果到控制台  
        result.print();  
  
        // 执行任务  
        env.execute("Process Element Example");  
    }  
}

scala:

class MyKeyedProcessFunction extends KeyedProcessFunction[String, Tuple2[String, Int], Tuple3[String, String, String]] {  
  
  override def processElement(value: Tuple2[String, Int],  
                                ctx: KeyedProcessFunction[String, Tuple2[String, Int], Tuple3[String, String, String]]#Context,  
                                out: Collector[Tuple3[String, String, String]]): Unit = {  
    // 处理每个元素,这里只是简单地将元素的值翻倍并输出  
    val key = value.f0  
    val valueToProcess = value.f1  
    val processedValue = valueToProcess * 2  
    val output = Tuple3(key, "processed", processedValue.toString)  
    out.collect(output)  
  }  
}
/**
在这个示例中,我们定义了一个名为 MyKeyedProcessFunction 的类,它继承自 KeyedProcessFunction。我们使用 Tuple2 类型作为输入元素,其中第一个字段是字符串类型的 key,第二个字段是整数值。输出使用 Tuple3 类型,其中第一个字段是 key,第二个字段是字符串 "processed",第三个字段是处理后的整数值。

在 processElement() 方法中,我们首先获取元素的 key 和值,然后对值进行翻倍处理。最后,我们将处理后的结果封装为 Tuple3 类型的输出,并通过 out.collect() 方法将其发送到下游操作。

请注意,这只是一个简单的示例,你可以根据自己的需求调整 processElement() 方法的逻辑来处理实际数据。
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值