flink窗口自定义时长和步长

目前flink对于时间窗口只能固定死步长和窗口时长大小,对于动态改变时间大小和步长大小不能支持,如果现有的代码需要改变步长和大小需要停止程序,需求代码,然后重新打包编译,这对于实时任务来说有风险,还会出现重复数据的风险,对于时间动态窗口网上资料较少,也很少有案例,我自己手动开发了一个样例,并且在本地跑通了,下面将代码给大家附上,供大家学习参考:

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.EventTimeTrigger;
import org.apache.flink.streaming.api.windowing.triggers.Trigger;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import zj_fk_window.ZjBroadcastConnectLog;
import zj_fk_window.ZujuanRequest;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static zj_fk_window.SideTimeWindowStep.getStepValue;

public class DynSlidingEventTimeWindows  extends WindowAssigner<Object, TimeWindow> {
    private static final long serialVersionUID = 1L;

    private final long size;

    private final long slide;

    private final long offset;

    //从原始数据中获取窗口长度
    private static ZjBroadcastConnectLog sizeTimeAdjustExtractor;
    //从原始数据中获取窗口步长
    private static ZjBroadcastConnectLog slideTimeAdjustExtractor;

    protected DynSlidingEventTimeWindows(long size, long slide, long offset) {
        if (Math.abs(offset) >= slide || size <= 0) {
            throw new IllegalArgumentException(
                    "SlidingEventTimeWindows parameters must satisfy "
                            + "abs(offset) < slide and size > 0");
        }

        this.size = size;
        this.slide = slide;
        this.offset = offset;
    }

    protected DynSlidingEventTimeWindows(long size, long slide, long offset, ZjBroadcastConnectLog sizeTimeAdjustExtractor, ZjBroadcastConnectLog slideTimeAdjustExtractor) {
        if (Math.abs(offset) >= slide || size <= 0) {
            throw new IllegalArgumentException(
                    "SlidingEventTimeWindows parameters must satisfy "
                            + "abs(offset) < slide and size > 0");
        }

        this.size = size;
        this.slide = slide;
        this.offset = offset;
        this.sizeTimeAdjustExtractor = sizeTimeAdjustExtractor;
        this.slideTimeAdjustExtractor = slideTimeAdjustExtractor;
    }

    //每次分配窗口的时候,都从数据里面抽取窗口与步长,如果存在就将新定义的长度以及步长作为新的长度与步长,这样就实现了动态调整
    @Override
    public Collection<TimeWindow> assignWindows(Object element, long timestamp, WindowAssignerContext context) {
        this.getElementAllWindows(Time.seconds(15), Time.seconds(1), Time.seconds(0),
                new ZjBroadcastConnectLog() {
            @Override
            public long reset(ZujuanRequest zr) {
                return Time.seconds(((ZjBroadcastConnectLog)element).getTime_count()).toMilliseconds();
            }

        }, new ZjBroadcastConnectLog() {
            @Override
            public long reset(ZujuanRequest zr) {
                //System.out.println("999999999999999999======"+((ZjBroadcastConnectLog)element).toString());

                int timeCount =  ((ZjBroadcastConnectLog)element).getTime_count();
                //System.out.println("timeCount======"+timeCount);

                //getStepValue(timeCount);
                //System.out.println("111111111111getStep_count======"+getStepValue(timeCount));
                return Time.seconds(getStepValue(((ZjBroadcastConnectLog)element).getTime_count())).toMilliseconds();
            }
        });

        long realSize = this.sizeTimeAdjustExtractor.reset((ZujuanRequest) element);
        long realSlide = this.slideTimeAdjustExtractor.reset((ZujuanRequest) element);
        if (timestamp > Long.MIN_VALUE) {
            List<TimeWindow> windows = new ArrayList<>((int) ((realSize == 0? size : realSize) / (realSlide == 0? slide:realSlide)));
            long lastStart = TimeWindow.getWindowStartWithOffset(timestamp, offset, (realSlide == 0? slide:realSlide));
            for (long start = lastStart; start > timestamp - (realSize == 0? size : realSize); start -= (realSlide == 0? slide:realSlide)) {
                windows.add(new TimeWindow(start, start + (realSize == 0? size : realSize)));
            }
            return windows;
        } else {
            throw new RuntimeException("timestamp is less than minvalue");
        }
    }

    public long getSize() {
        return size;
    }

    public long getSlide() {
        return slide;
    }

    @Override
    public Trigger<Object, TimeWindow> getDefaultTrigger(StreamExecutionEnvironment env) {
        return EventTimeTrigger.create();
    }

    @Override
    public String toString() {
        return "SlidingEventTimeWindows(" + size + ", " + slide + ")";
    }

    /**     * Creates a new {@code SlidingEventTimeWindows} {@link WindowAssigner} that assigns elements to     * sliding time windows based on the element timestamp.     *     * @param size The size of the generated windows.     * @param slide The slide interval of the generated windows.     * @return The time policy.     */
    public static DynSlidingEventTimeWindows of(Time size, Time slide) {
        return new DynSlidingEventTimeWindows(size.toMilliseconds(), slide.toMilliseconds(), 0);
    }

    /**     * Creates a new {@code SlidingEventTimeWindows} {@link WindowAssigner} that assigns elements to     * time windows based on the element timestamp and offset.     *     * <p>For example, if you want window a stream by hour,but window begins at the 15th minutes of     * each hour, you can use {@code of(Time.hours(1),Time.minutes(15))},then you will get time     * windows start at 0:15:00,1:15:00,2:15:00,etc.     *     * <p>Rather than that,if you are living in somewhere which is not using UTC±00:00 time, such as     * China which is using UTC+08:00,and you want a time window with size of one day, and window     * begins at every 00:00:00 of local time,you may use {@code of(Time.days(1),Time.hours(-8))}.     * The parameter of offset is {@code Time.hours(-8))} since UTC+08:00 is 8 hours earlier than     * UTC time.     *     * @param size The size of the generated windows.     * @param slide The slide interval of the generated windows.     * @param offset The offset which window start would be shifted by.     * @return The time policy.     */
    public static DynSlidingEventTimeWindows of(Time size, Time slide, Time offset) {
        return new DynSlidingEventTimeWindows(
                size.toMilliseconds(), slide.toMilliseconds(), offset.toMilliseconds());
    }

    public static DynSlidingEventTimeWindows of(Time size, Time slide, Time offset,ZjBroadcastConnectLog sizeTimeAdjustExtractor,ZjBroadcastConnectLog slideTimeAdjustExtractor) {
        return new DynSlidingEventTimeWindows(
                size.toMilliseconds(), slide.toMilliseconds(), offset.toMilliseconds(),
                sizeTimeAdjustExtractor,slideTimeAdjustExtractor);
    }

    public static DynSlidingEventTimeWindows getElementAllWindows(Time size, Time slide, Time offset, ZjBroadcastConnectLog sizeTimeAdjustExtractor,
                                                                  ZjBroadcastConnectLog slideTimeAdjustExtractor) {
        return new DynSlidingEventTimeWindows(
                size.toMilliseconds(), slide.toMilliseconds(), offset.toMilliseconds(),
                sizeTimeAdjustExtractor,slideTimeAdjustExtractor);
    }
    @Override
    public TypeSerializer<TimeWindow> getWindowSerializer(ExecutionConfig executionConfig) {
        return new TimeWindow.Serializer();
    }

    @Override
    public boolean isEventTime() {
        return true;
    }

}

调用的时候通过将之前定义的窗口来动态传入参数实现动态时间窗口
.window(
        //TumblingEventTimeWindows.of(Time.milliseconds(6000L))
        //SlidingEventTimeWindows.of(Time.milliseconds(6000L),Time.milliseconds(3000L))
        //EventTimeSessionWindows.withGap(Time.milliseconds(4000L))
        DynSlidingEventTimeWindows.getElementAllWindows(Time.seconds(60), Time.seconds(1), Time.seconds(0),
                new ZjBroadcastConnectLog() {
                    @Override
                    public long reset(ZujuanRequest zr) {
                        return Time.seconds(((ZjBroadcastConnectLog) zr).getTime_count()).toMilliseconds();
                    }

                }, new ZjBroadcastConnectLog() {
                    @Override
                    public long reset(ZujuanRequest zr) {
                        return Time.seconds(getStepValue(((ZjBroadcastConnectLog) zr).getTime_count())).toMilliseconds();
                    }

                })
)

对于这个时间动态窗口可以解决重启程序的风险,并且实用性更强,大家都可以试试这个函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值