Flink自定義Window----自定義Evictor(驅逐者)

在看flink Window 機制的相關博客時,看到有個同學的需求很有趣,

"如何讓一個DataStream中的某個字段與21天前的該字段做比較?"

該同學給定了一個大小21天,每一天滑動一次的window

解決方案:
在其TimeWindow上進行修改,挖空中間不需要的20天,整出來一個門字形的TimeWindow,

這樣只剩下第一天和最後一天的兩個門腳數據,以進行後續的操作,如比較

具體實現依靠自定義Evictor實現,

這樣只需要應用該GantryTimeEvictor 即可

keyedStream
    .window(SlidingEventTimeWindows.of(Time.days(21), Time.days(
    .evictor(GantryTimeEvictor.of(Time.days(1)));
代碼如下:

package com.run;
 
import org.apache.flink.api.common.time.Time;
import org.apache.flink.streaming.api.windowing.evictors.Evictor;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.streaming.runtime.operators.windowing.TimestampedValue;
 
import java.util.Iterator;
 
/**
 * @Author MrBlack
 * @Date 2019/12/17 017 下午 6:43
 **/
public class GantryTimeEvictor implements Evictor<Object, TimeWindow> {
 
    // 雙腳寬度
    private final long gantryFootSize;
    // 是否在應用窗口後驅除
    private final boolean doEvictAfter;
 
    public GantryTimeEvictor(long gantryFootSize) {
        this.gantryFootSize = gantryFootSize;
        this.doEvictAfter = false;
    }
 
    public GantryTimeEvictor(long gantryFootSize, boolean doEvictAfter) {
        this.gantryFootSize = gantryFootSize;
        this.doEvictAfter = doEvictAfter;
    }
 
    /**
     * 在應用窗口前驅除不需要的元素
     *
     * @param elements   當前在窗口中的元素
     * @param size       窗口中元素數量
     * @param timeWindow 當前窗口
     * @param ctx        Evictor上下文
     */
    @Override
    public void evictBefore(Iterable<TimestampedValue<Object>> elements, int size, TimeWindow timeWindow, EvictorContext ctx) {
        if (!this.doEvictAfter) {
            this.evict(elements, size, timeWindow, ctx);
        }
    }
 
    /**
     * 在應用窗口後驅除不需要的元素
     */
    @Override
    public void evictAfter(Iterable<TimestampedValue<Object>> elements, int size, TimeWindow timeWindow, EvictorContext ctx) {
        if (this.doEvictAfter) {
            this.evict(elements, size, timeWindow, ctx);
        }
    }
 
    private void evict(Iterable<TimestampedValue<Object>> elements, int size, TimeWindow timeWindow, EvictorContext ctx) {
        if (this.hasTimestamp(elements)) {
            long evictCutBegin = timeWindow.getStart() + this.gantryFootSize;
            long evictCutEnd = timeWindow.getEnd() - this.gantryFootSize;
            Iterator iterator = elements.iterator();
            while (iterator.hasNext()) {
                TimestampedValue<Object> record = (TimestampedValue) iterator.next();
                if (record.getTimestamp() >= evictCutBegin && record.getTimestamp() <= evictCutEnd) {
                    iterator.remove();
                }
            }
        }
    }
 
    /**
     * 判斷元素是否有時間戳
     *
     * @param elements
     * @return
     */
    private boolean hasTimestamp(Iterable<TimestampedValue<Object>> elements) {
        Iterator<TimestampedValue<Object>> it = elements.iterator();
        return it.hasNext() && it.next().hasTimestamp();
    }
 
    public static GantryTimeEvictor of(Time gantryFootSize) {
        return new GantryTimeEvictor(gantryFootSize.toMilliseconds());
    }
 
    public static GantryTimeEvictor of(Time gantryFootSize, boolean doEvictAfter) {
        return new GantryTimeEvictor(gantryFootSize.toMilliseconds(), doEvictAfter);
    }
}
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章