Flink之流的转换

ProcessFuncion处理函数

  • 功能
    • 拥有富函数功能
      • 生命周期方法
      • 状态编程
    • 对元素的处理功能processElement, 在不同的处理函数中,该方法的名字略有区别
    • 定时器编程
      • TimeService:定时服务,可以用于注册定时器,删除定时器
      • ontimer():定时器触发后会自动调用该方法,我们将需要完成的工作写到该方法中
    • 侧输出流
  • 分类
    • processFunction: 普通流DataStream调用
    • keyedProcessFunction: KeyedStream, 经过Keyby的数据流
    • ProcessWindowFunction:按键分区经过window操作的数据流,WindowedStream,全窗口函数
    • ProcessAllWindowFunction:非按键分区的window数据流调用
    • CoProcessFunction:ConnectedStreams, 由两个数据流经过connect后得到的,没有经过keyby时调用
    • ProcessJoinFunction:IntervalJoined , 两个流经过IntervalJoin后得到的流
    • BroadcastProcessFunction:一个普通流connect广播流后得到,之后调用process需要传入该Function
    • KeyedBroadcastProcessFunction: 一个keyby流connect广播流后得到

常用流之间的转换关系

  • SingleOutputDataSteam是继承自DataStream的。
  • window操作必须是基于keyby流
  • 特殊流经过reduce, aggreagate,process, apply等聚合操作后就变为SingleOutputDataStream

processFunction的定时器方法

定时服务 和定时器

  • TimerService:定时服务,用于注册定时器,删除定时
    • long currentProcessingTime():获取当前的处理时间
    • registerProcessingTimer(): 注册处理时间定时器
    • registerEventTimeTimer():注册事件时间定时器
    • currentWatermark():获取当前水位线
    • deleteEventTimeTimer():注册事件时间定时器
  • Timer:定时器,在未来的某个时间注册一个事件,定时器触发,会执行定义的事件
  • ontimer(): 定时器触发以后,会自动调用该方法
  • 注意:
    • 要定时先keyby, 设置定时器必须基于一个keyby流
    • 同一个key在注册多个相同时间的定时器,未来之后触发一次,不同的key注册相同时间的定时器,每个key都会触发一次。

TopN 实现

java 复制代码
/**
 * title:
 *
 * @Author 浪拍岸
 * @Create 11/12/2023 下午3:19
 * @Version 1.0
 *
 * 实时统计一段时间的热门URL
 * 例如:10秒内最热门的两个URL链接,并且每5秒更新一次
 *
 * 方案1:不进行keyby操作,将所有URL数据统一往一个窗口
 * 中收集,并且使用全量聚合,等到窗口触发计算时,在处理函数中
 * 对窗口内所有数据进行汇总处理
 *
 */
public class Flink03_TopN {
    public static void main(String[] args) {
        //1.创建运行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        //默认是最大并行度
        env.setParallelism(1);

        SingleOutputStreamOperator<Event> ds = Flink06_EventSource.getEventSource(env)
                .assignTimestampsAndWatermarks(
                        WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO)
                                .withTimestampAssigner(
                                        (event, ts) -> event.getTs()
                                )
                );

        ds.print("input");

        ds.windowAll(
//                TumblingEventTimeWindows.of(Time.seconds(10))
                SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5))
        ).process(
                new ProcessAllWindowFunction<Event, String, TimeWindow>() {
                    @Override
                    public void process(ProcessAllWindowFunction<Event, String, TimeWindow>.Context context, Iterable<Event> elements, Collector<String> out) throws Exception {
                        //统计每个URL的点击次数

                        long start = context.window().getStart();
                        long end = context.window().getEnd();

                        HashMap<String, Long> urlCountMap = new HashMap<>();

                        for (Event element : elements) {
                            Long count = urlCountMap.getOrDefault(element.getUrl(), 0L);
                            urlCountMap.put(element.getUrl(), count+1);
                        }

                        //将map结构转换为list
//                        ArrayList<UrlUserCount> urlCountList = new ArrayList<>(urlCountMap.size());

                        List<UrlUserCount> urlUserCountList = urlCountMap.entrySet().stream().map(
                                entry -> new UrlUserCount(entry.getKey(), entry.getValue(), start, end)
                        ).collect(Collectors.toList());

                        urlUserCountList.sort(
                                new Comparator<UrlUserCount>() {
                                    @Override
                                    public int compare(UrlUserCount o1, UrlUserCount o2) {
                                        return Long.compare(o2.getCount(), o1.getCount());
                                    }
                                }
                        );

                        //取topN
                        StringBuilder result = new StringBuilder("*******************************\n");
                        for (int i = 0; i < Math.min(2,urlUserCountList.size()); i++) {
                            UrlUserCount urlUserCount = urlUserCountList.get(i);
                            result.append("TOP."+(i+1)+" "+urlUserCount+"\n");

                        }
                        result.append("*****************************************\n");
                        //输出
                        out.collect(result.toString());
                    }
                }
        ).print();


        try {
            env.execute();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
相关推荐
今晚务必早点睡17 分钟前
微服务改数据库密码后服务仍能访问?一次“看似异常、实则常见”的生产现象全解析
数据库·微服务·oracle
老师我太想进步了20262 小时前
cmd连接MySQL及相关查询
数据库·mysql
小鸡脚来咯2 小时前
Git 新手入门指南
大数据·git·elasticsearch
難釋懷5 小时前
Redis命令-Set命令
数据库·redis·缓存
Linux-palpitate5 小时前
PostgreSQL(PG)的1主2从集群部署安装
数据库·postgresql
heartbeat..5 小时前
数据库基础知识体系:概念、约束、范式与国产产品
java·数据库·学习笔记·国产数据库
说私域6 小时前
基于AI智能名片链动2+1模式服务预约商城系统的社群运营与顾客二次消费吸引策略研究
大数据·人工智能·小程序·开源·流量运营
山峰哥6 小时前
数据库工程核心:SQL调优让查询效率飙升的实战密码
网络·汇编·数据库·sql·编辑器
Coder_Boy_7 小时前
基于SpringAI的在线考试系统-DDD业务领域模块设计思路
java·数据库·人工智能·spring boot·ddd
小雪_Snow7 小时前
Windows 安装 MySQL 8.0 教程【安装包方式】
数据库·mysql