一、需求
从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 +
'}';
}
}
}