需求
网关上报的数据以整点时间:进行10分钟,半小时,一小时各统计一下最大值,最小值,平均值,总数和次数;
分析
需要开窗函数,5分钟的窗口以 00;05;10;15.。。。为起点开窗。
10分钟的窗口以 00;10;20;30.。。。为起点开窗。
flink 的滚动开窗时间是以数据发生时间,偏移量,窗口大小 判定的
public static long getWindowStartWithOffset(long timestamp, long offset, long windowSize) {
return timestamp - (timestamp - offset + windowSize) % windowSize;
}
时间的执行时间是不确定的,,窗口大小是确定的,偏移量需要自己计算,
这似乎不好弄!
解决方案
使用自定义窗口,用自己的方式去约定窗口的开始时间;如下是以10分钟为窗口进行自定义开窗
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import org.apache.flink.api.common.ExecutionConfig;
import org.apache.flink.api.common.typeutils.TypeSerializer;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.WindowAssigner;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.triggers.ProcessingTimeTrigger;
import org.apache.flink.streaming.api.windowing.triggers.Trigger;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import java.util.Collection;
import java.util.Collections;
public class MyEventTimeWindow extends WindowAssigner<Object, TimeWindow> {
// 窗口的大小
private final long size;
// 多长时间滑动一次
private final long slide;
// 时间点
private final int startTime;
protected MyEventTimeWindow(long size, long slide, int startTime) {
this.size = size;
this.slide = slide;
this.startTime = startTime;
}
public static MyEventTimeWindow of(Time size, Time slide, int startTime) {
return new MyEventTimeWindow(size.toMilliseconds(), slide.toMilliseconds(), startTime);
}
public static MyEventTimeWindow of(Time size, Time slide) {
return new MyEventTimeWindow(size.toMilliseconds(), slide.toMilliseconds(), 0);
}
@Override
public Collection<TimeWindow> assignWindows(Object element, long timestamp, WindowAssignerContext context) {
timestamp = context.getCurrentProcessingTime();
int minute = DateUtil.date(timestamp).minute();
// 当时 以10为倍数的起点的余数值
int t10Minys = minute%startTime;
// 是当前分钟的第几秒
int second = DateUtil.date(timestamp).second();
// 是当前秒的第几毫秒
int millsecond = DateUtil.date(timestamp).millsecond();
// 当前时间向前偏移; 如果是07分钟的数据,开始时间就是00;
long lastStart = DateUtil.date(timestamp).offset(DateField.MILLISECOND,-((t10Minys*60+second)*1000+millsecond)).getTime();
return Collections.singletonList(new TimeWindow(lastStart, lastStart + this.size));
}
@Override
public Trigger<Object, TimeWindow> getDefaultTrigger(StreamExecutionEnvironment streamExecutionEnvironment) {
return ProcessingTimeTrigger.create();
}
@Override
public TypeSerializer<TimeWindow> getWindowSerializer(ExecutionConfig executionConfig) {
return new TimeWindow.Serializer();
}
@Override
public boolean isEventTime() {
return true;
}
}