https://github.com/zq2599/blog_demosjava
内容:全部原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;git
从上图可见,CoProcessFunction和KeyedProcessFunction的继承关系同样,另外CoProcessFunction自身也很简单,在<font color="blue">processElement1</font>和<font color="blue">processElement2</font>中分别处理两个上游流入的数据便可,而且也支持定时器设置;程序员
本篇我们要开发的应用,其功能很是简单,描述以下:github
接下来开始编码;shell
若是您不想写代码,整个系列的源码可在GitHub下载到,地址和连接信息以下表所示(https://github.com/zq2599/blo...数据库
名称 | 连接 | 备注 |
---|---|---|
项目主页 | https://github.com/zq2599/blo... | 该项目在GitHub上的主页 |
git仓库地址(https) | https://github.com/zq2599/blo... | 该项目源码的仓库地址,https协议 |
git仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |
这个git项目中有多个文件夹,本章的应用在<font color="blue">flinkstudy</font>文件夹下,以下图红框所示:apache
从上面的描述可见,<font color="blue">AbstractCoProcessFunctionExecutor</font>作了不少事情,惟独没有实现双流链接后的具体业务逻辑,这些没有作的是留给子类来实现的,整个三部曲系列的重点都集中在AbstractCoProcessFunctionExecutor的子类上,把双流链接后的业务逻辑作好,以下图所示,红色为CoProcessFunction的业务代码,其余的都在抽象类中完成:windows
package com.bolingcavalry.coprocessfunction; import org.apache.flink.api.common.functions.MapFunction; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.util.StringUtils; public class WordCountMap implements MapFunction<String, Tuple2<String, Integer>> { @Override public Tuple2<String, Integer> map(String s) throws Exception { if(StringUtils.isNullOrWhitespaceOnly(s)) { System.out.println("invalid line"); return null; } String[] array = s.split(","); if(null==array || array.length<2) { System.out.println("invalid line for array"); return null; } return new Tuple2<>(array[0], Integer.valueOf(array[1])); } }
package com.bolingcavalry.coprocessfunction; import org.apache.flink.api.java.tuple.Tuple; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.streaming.api.datastream.KeyedStream; import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.functions.co.CoProcessFunction; /** * @author will * @email zq2599@gmail.com * @date 2020-11-09 17:33 * @description 串起整个逻辑的执行类,用于体验CoProcessFunction */ public abstract class AbstractCoProcessFunctionExecutor { /** * 返回CoProcessFunction的实例,这个方法留给子类实现 * @return */ protected abstract CoProcessFunction< Tuple2<String, Integer>, Tuple2<String, Integer>, Tuple2<String, Integer>> getCoProcessFunctionInstance(); /** * 监听根据指定的端口, * 获得的数据先经过map转为Tuple2实例, * 给元素加入时间戳, * 再按f0字段分区, * 将分区后的KeyedStream返回 * @param port * @return */ protected KeyedStream<Tuple2<String, Integer>, Tuple> buildStreamFromSocket(StreamExecutionEnvironment env, int port) { return env // 监听端口 .socketTextStream("localhost", port) // 获得的字符串"aaa,3"转成Tuple2实例,f0="aaa",f1=3 .map(new WordCountMap()) // 将单词做为key分区 .keyBy(0); } /** * 若是子类有侧输出须要处理,请重写此方法,会在主流程执行完毕后被调用 */ protected void doSideOutput(SingleOutputStreamOperator<Tuple2<String, Integer>> mainDataStream) { } /** * 执行业务的方法 * @throws Exception */ public void execute() throws Exception { final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // 并行度1 env.setParallelism(1); // 监听9998端口的输入 KeyedStream<Tuple2<String, Integer>, Tuple> stream1 = buildStreamFromSocket(env, 9998); // 监听9999端口的输入 KeyedStream<Tuple2<String, Integer>, Tuple> stream2 = buildStreamFromSocket(env, 9999); SingleOutputStreamOperator<Tuple2<String, Integer>> mainDataStream = stream1 // 两个流链接 .connect(stream2) // 执行低阶处理函数,具体处理逻辑在子类中实现 .process(getCoProcessFunctionInstance()); // 将低阶处理函数输出的元素所有打印出来 mainDataStream.print(); // 侧输出相关逻辑,子类有侧输出需求时重写此方法 doSideOutput(mainDataStream); // 执行 env.execute("ProcessFunction demo : CoProcessFunction"); } }
关键点之五:doSideOutput方法中啥也没作,可是在主流程代码的末尾会被调用,若是子类有侧输出(SideOutput)的需求,重写此方法便可,此方法的入参是处理过的数据集,能够从这里取得侧输出;api
package com.bolingcavalry.coprocessfunction; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.streaming.api.functions.co.CoProcessFunction; import org.apache.flink.util.Collector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CollectEveryOne extends AbstractCoProcessFunctionExecutor { private static final Logger logger = LoggerFactory.getLogger(CollectEveryOne.class); @Override protected CoProcessFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, Tuple2<String, Integer>> getCoProcessFunctionInstance() { return new CoProcessFunction<Tuple2<String, Integer>, Tuple2<String, Integer>, Tuple2<String, Integer>>() { @Override public void processElement1(Tuple2<String, Integer> value, Context ctx, Collector<Tuple2<String, Integer>> out) { logger.info("处理1号流的元素:{},", value); out.collect(value); } @Override public void processElement2(Tuple2<String, Integer> value, Context ctx, Collector<Tuple2<String, Integer>> out) { logger.info("处理2号流的元素:{}", value); out.collect(value); } }; } public static void main(String[] args) throws Exception { new CollectEveryOne().execute(); } }
12:45:38,774 INFO CollectEveryOne - 处理1号流的元素:(aaa,111), (aaa,111) 12:45:43,816 INFO CollectEveryOne - 处理2号流的元素:(bbb,222) (bbb,222)
微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
https://github.com/zq2599/blog_demos