Flink window Trigger

时间:2025-04-09 07:10:09
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * /licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.tigerclub.grassland.function; import org.apache.flink.annotation.PublicEvolving; import org.apache.flink.api.common.state.ValueState; import org.apache.flink.api.common.state.ValueStateDescriptor; import org.apache.flink.api.common.typeinfo.Types; import org.apache.flink.streaming.api.windowing.triggers.Trigger; import org.apache.flink.streaming.api.windowing.triggers.TriggerResult; import org.apache.flink.streaming.api.windowing.windows.TimeWindow; import java.io.IOException; /** * A {@link Trigger} that fires once the watermark passes the end of the window * to which a pane belongs. * * @see */ @PublicEvolving public class EventTimeOrIntervalTrigger extends Trigger<Object, TimeWindow> { private static final long serialVersionUID = 1L; ValueStateDescriptor<Integer> triggerStateDescriptor; public EventTimeOrIntervalTrigger(String instanceId) { triggerStateDescriptor = new ValueStateDescriptor<Integer>("triggerState" + instanceId, Types.INT); } @Override public TriggerResult onElement(Object element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception { ValueState<Integer> triggerState = ctx.getPartitionedState(triggerStateDescriptor); Integer state = triggerState.value(); if (state == null) {// first element in this window long processTriggerTime = ctx.getCurrentProcessingTime() + (long) ((window.getEnd() - window.getStart()) * 1.2); ctx.registerProcessingTimeTimer(processTriggerTime); ctx.registerEventTimeTimer(window.maxTimestamp()); triggerState.update(1); return TriggerResult.CONTINUE; } if (window.maxTimestamp() <= ctx.getCurrentWatermark()) { // if the watermark is already past the window fire immediately return TriggerResult.FIRE; } return TriggerResult.CONTINUE; } @Override public TriggerResult onEventTime(long time, TimeWindow window, TriggerContext ctx) throws IOException { if (time == window.maxTimestamp()) { ValueState<Integer> triggerState = ctx.getPartitionedState(triggerStateDescriptor); if (triggerState.value() != null && triggerState.value() != 2) { triggerState.update(3); return TriggerResult.FIRE; } } return TriggerResult.CONTINUE; } @Override public TriggerResult onProcessingTime(long time, TimeWindow window, TriggerContext ctx) throws Exception { ValueState<Integer> triggerState = ctx.getPartitionedState(triggerStateDescriptor); if (triggerState != null && triggerState.value() != 3) { triggerState.update(2); return TriggerResult.FIRE_AND_PURGE; } else { return TriggerResult.CONTINUE; } } @Override public void clear(TimeWindow window, TriggerContext ctx) throws Exception { ctx.deleteEventTimeTimer(window.maxTimestamp()); } @Override public boolean canMerge() { return true; } @Override public void onMerge(TimeWindow window, OnMergeContext ctx) { // only register a timer if the watermark is not yet past the end of the merged window // this is in line with the logic in onElement(). If the watermark is past the end of // the window onElement() will fire and setting a timer here would fire the window twice. long windowMaxTimestamp = window.maxTimestamp(); if (windowMaxTimestamp > ctx.getCurrentWatermark()) { ctx.registerEventTimeTimer(windowMaxTimestamp); } } @Override public String toString() { return "EventTimeTrigger()"; } /** * Creates an event-time trigger that fires once the watermark passes the end of the window. * * <p>Once the trigger fires all elements are discarded. Elements that arrive late immediately * trigger window evaluation with just this one element. */ public static EventTimeOrIntervalTrigger create(String instanceId) { return new EventTimeOrIntervalTrigger(instanceId); } }