2.3 Function的定义与实现

我们已经知道,DataStream转换操作中的数据处理逻辑主要是通过自定义函数实现的,Function作为Flink中最小的数据处理单元,在Flink中占据非常重要的地位。和Java提供的Function接口类似,Flink实现的Function接口专门用于处理接入的数据元素。StreamOperator负责对内部Function的调用和执行,当StreamOperator被Task调用和执行时,StreamOperator会将接入的数据元素传递给内部Function进行处理,然后将Function处理后的结果推送给下游的算子继续处理。

如图2-7所示,Function接口是所有自定义函数的父类,图中MapFunction和FlatMapFunction都是直接继承自Function接口,并提供各自的数据处理方法。其中MapFunction接口提供了map()方法实现数据的一对一转换处理,FlatMapFunction提供了flatMap()方法实现对输入数据元素的一对多转换,即输入一条数据产生多条输出结果。在flatMap()方法中通过Collector接口实现了对输出结果的收集操作。当然还有其他类型的Function实现,例如FilterFunction等,由于篇幅有限,这里没有全部介绍。

图2-7 Function UML关系图

从图2-7中也可以看出,Flink提供了RichFunction接口实现对有状态计算的支持,RichFunction接口除了包含open()和close()方法之外,还提供了获取RuntimeContext的方法,并在AbstractRichFunction抽象类类中提供了对RichFunction接口的基本实现。RichMapFunction和RichFlatMapFunction接口实现类最终通过AbstractRichFunction提供的getRuntimeContext()方法获取RuntimeContext对象,进而操作状态数据。

用户可以选择相应的Function接口实现不同类型的业务转换逻辑,例如MapFunction接口中提供的map()方法可以实现数据元素的一对一转换。对于普通的Function转换没有太多需要展开的内容,接下来我们重点了解RichFunction的实现细节,具体了解Flink中如何通过RichFunction实现有状态计算。