【博学谷学习记录】超强总结,用心分享| DataStream

一、需求

从socket获取数据,转换成水位传感器类,基于事件时间,每5秒生成一个滚动窗口,来计算传感器水位信息

类名:WaterSensor
String id,id号
Integer vc,valueCount水位的值
Long ts,timestamp,时间戳

二、分析

//1.构建流式执行环境

//2.读取socket数据源

//3.对数据进行处理
//3.1 把socket数据转换为水位传感器的类WaterSensor
//3.2 给数据分配时间戳和水印,这里指定为单调递增水印
//3.3 对数据进行分组/分流
//3.4 划分窗口,这里指定为滚动窗口,窗口大小为5秒
//3.5 进行处理(介绍一个低阶API process方法)

//4.数据输出

//5.启动流式任务
三、实现

package day07;

import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;

/**
 * @author: itcast
 * @date: 2023/4/8 20:37
 * @desc: 需求:从socket获取数据,转换成水位传感器类,基于事件时间,每5秒生成一个滚动窗口,来计算传感器水位信息
 *
 * 类名:WaterSensor
 * String id,id号
 * Integer vc,valueCount水位的值
 * Long ts,timestamp,时间戳
 */
public class Demo01_MonotonousTimestamp {
    public static void main(String[] args) throws Exception {
        //1.构建流式执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        //2.读取socket数据源
        DataStreamSource<String> source = env.socketTextStream("node1", 9999);

        //3.对数据进行处理
        //3.1 把socket数据转换为水位传感器的类WaterSensor
        SingleOutputStreamOperator<WaterSensor> mapData = source.map(new MapFunction<String, WaterSensor>() {
            @Override
            public WaterSensor map(String value) throws Exception {
                String[] lines = value.split(",");
                return new WaterSensor(lines[0], Integer.parseInt(lines[1]), Long.parseLong(lines[2]));
            }
        });
        //3.2 给数据分配时间戳和水印,这里指定为单调递增水印
        /**
         * Flink 的水印策略有四种:
         * WatermarkStrategy.forMonotonousTimestamps:单调递增水印,类似于延迟设置为0,用的较少
         * WatermarkStrategy.forBoundedOutOfOrderness:固定延迟水印,类似于延迟时间设置为2,用的最多
         * WatermarkStrategy.forGenerator:自定义水印,几乎不用
         * WatermarkStrategy.noWatermarks:没有水印,几乎不用
         */
        SingleOutputStreamOperator<WaterSensor> watermarkData = mapData.assignTimestampsAndWatermarks(WatermarkStrategy
                .<WaterSensor>forMonotonousTimestamps()
                .withTimestampAssigner(new SerializableTimestampAssigner<WaterSensor>() {
            @Override
            public long extractTimestamp(WaterSensor element, long recordTimestamp) {
                return element.getTs() * 1000;
            }
        }));
        //3.3 对数据进行分组/分流
        SingleOutputStreamOperator<String> result = watermarkData.keyBy(value -> value.getId())
                //3.4 划分窗口,这里指定为滚动窗口,窗口大小为5秒
                .window(TumblingEventTimeWindows.of(Time.seconds(5)))
                //3.5 进行处理(介绍一个低阶API process方法)
                /**
                 * ProcessWindowFunction用于处理其他方法处理不了的需求。是一个底层的API。
                 * ProcessWindowFunction对象有四个参数,分别是:
                 * 参数一:The type of the input value,输入的数据类型,这里就是WaterSensor
                 * 参数二: The type of the output value,输出的数据类型,这里可以给定为String
                 * 参数三:The type of the key,分组的数据类型,这里是就是id的类型,String
                 * 参数四:The type of that this window function can be applied on,窗口函数的类型
                 */
                .process(new ProcessWindowFunction<WaterSensor, String, String, TimeWindow>() {
                    /**
                     * process方法,用来处理数据的逻辑的。
                     * @param s 分组的元素
                     * @param context 流式程序的上下文对象,可以获取一些任务的额外信息
                     * @param elements 窗口内的数据元素
                     * @param out 收集者对象,用来收集最终结果的
                     * @throws Exception 异常信息
                     */
                    @Override
                    public void process(String s, Context context, Iterable<WaterSensor> elements, Collector<String> out) throws Exception {
                        out.collect("分组的key为:" + s +
                                "\n窗口内的数据为:" + elements +
                                "\n窗口内的数据量为:" + elements.spliterator().estimateSize() +
                                "\n窗口的大小为:[" + context.window().getStart() + "," + context.window().getEnd() + ")" +
                                "\n当前水印时间为:" + context.currentWatermark());
                    }
                });

        //4.数据输出
        result.print();

        //5.启动流式任务
        env.execute();

    }


    /**
     * 自定义的WaterSensor水位传感器的类
     */
    private static class WaterSensor {
        //id号
        private String id;
        //水位的值vc
        private Integer vc;
        //时间戳
        private Long ts;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public Integer getVc() {
            return vc;
        }

        public void setVc(Integer vc) {
            this.vc = vc;
        }

        public Long getTs() {
            return ts;
        }

        public void setTs(Long ts) {
            this.ts = ts;
        }

        /**
         * 无参构造器
         */
        public WaterSensor() {
        }

        /**
         * 全参构造器
         * @param id id好
         * @param vc 值
         * @param ts 时间戳
         */
        public WaterSensor(String id, Integer vc, Long ts) {
            this.id = id;
            this.vc = vc;
            this.ts = ts;
        }

        /**
         * 重写toString方法
         * @return
         */
        @Override
        public String toString() {
            return "WaterSensor{" +
                    "id='" + id + '\'' +
                    ", vc=" + vc +
                    ", ts=" + ts +
                    '}';
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值