import org.apache.flink.api.common.state.ReducingState;
import org.apache.flink.api.common.state.ReducingStateDescriptor;
import org.apache.flink.api.common.typeutils.base.LongSerializer;
import org.apache.flink.api.common.typeutils.base.IntSerializer;
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.Window;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* @Auther WeiJiQian
* @描述 CountAndTimeTrigger : 满足一定条数和时间触发
* * 条数的触发使用计数器计数
* * 时间的触发,使用 flink 的 timerServer,注册触发器触发
*/
public class CountAndTimeTrigger<W extends Window> extends Trigger<Object, W> {
private Logger logger = LoggerFactory.getLogger(this.getClass());
// 触发的条数
private final long size;
// 触发的时长
private final long interval;
private static final long serialVersionUID = 1L;
// 条数计数器
private final ReducingStateDescriptor<Integer> countStateDesc =
new ReducingStateDescriptor<>("count", new ReduceSum(), IntSerializer.INSTANCE);
// 时间计数器,保存下一次触发的时间
private final ReducingStateDescriptor<Long> timeStateDesc =
new ReducingStateDescriptor<>("fire-interval", new ReduceMin(), LongSerializer.INSTANCE); public CountAndTimeTrigger(long size, long interval) {
this.size = size;
this.interval = interval;
} // 每条元素到来时.
@Override
public TriggerResult onElement(Object element, long timestamp, W window, TriggerContext ctx) throws Exception {
// 注册窗口结束的触发器, 不需要会自动触发
// ctx.registerProcessingTimeTimer(window.maxTimestamp());
// count
ReducingState<Integer> count = ctx.getPartitionedState(countStateDesc);
//interval
ReducingState<Long> fireTimestamp = ctx.getPartitionedState(timeStateDesc);
// 每条数据 counter + 1
count.add(1);
if (count.get() >= size) {
System.out.println("窗口结束: 计数器触发 count : {}"+ count.get());
// 满足条数的触发条件,先清 0 条数计数器
count.clear();
// 满足条数时也需要清除时间的触发器,如果不是创建结束的触发器
if (fireTimestamp.get() != window.maxTimestamp()) {
// logger.info("delete trigger : {}, {}", sdf.format(fireTimestamp.get()), fireTimestamp.get());
ctx.deleteProcessingTimeTimer(fireTimestamp.get());
}
fireTimestamp.clear();
// fire 触发计算
return TriggerResult.FIRE;
} // 触发之后,下一条数据进来才设置时间计数器注册下一次触发的时间 timestamp = ctx.getCurrentProcessingTime();
// timestamp = System.currentTimeMillis();
if (fireTimestamp.get() == null) {
// long start = timestamp - (timestamp % interval);
long nextFireTimestamp = timestamp + interval;
// logger.info("register trigger : {}, {}", sdf.format(nextFireTimestamp), nextFireTimestamp);
ctx.registerProcessingTimeTimer(nextFireTimestamp);
fireTimestamp.add(nextFireTimestamp);
}
return TriggerResult.CONTINUE;
} // 处理时间到的时候,开始处理
@Override
public TriggerResult onProcessingTime(long time, W window, TriggerContext ctx) throws Exception { // count
ReducingState<Integer> count = ctx.getPartitionedState(countStateDesc);
//interval
ReducingState<Long> fireTimestamp = ctx.getPartitionedState(timeStateDesc); // time trigger and window end
if (fireTimestamp.get() != null && time == window.maxTimestamp()) {
System.out.println("窗口结束: 正常结束 {}" + time);
// 窗口结束,清0条数和时间的计数器
count.clear();
ctx.deleteProcessingTimeTimer(fireTimestamp.get());
fireTimestamp.clear();
return TriggerResult.FIRE_AND_PURGE;
} else if (fireTimestamp.get() != null && fireTimestamp.get().equals(time)) {
System.out.println("窗口结束:时间计数器触发, time : {}" + time);
// 时间计数器触发,清0条数和时间计数器
count.clear();
fireTimestamp.clear();
return TriggerResult.FIRE;
}
return TriggerResult.CONTINUE;
} @Override
public TriggerResult onEventTime(long time, W window, TriggerContext ctx) throws Exception {
// count
ReducingState<Integer> count = ctx.getPartitionedState(countStateDesc);
//interval
ReducingState<Long> fireTimestamp = ctx.getPartitionedState(timeStateDesc); // time trigger and window end
if (time == window.maxTimestamp()) {
System.out.println("窗口结束 : {}"+ time);
// 窗口结束,清0条数和时间的计数器
count.clear();
ctx.deleteProcessingTimeTimer(fireTimestamp.get());
fireTimestamp.clear();
return TriggerResult.FIRE_AND_PURGE;
} else if (fireTimestamp.get() != null && fireTimestamp.get().equals(time)) {
System.out.println("时间计数器触发, time : {}"+ time);
// 时间计数器触发,清0条数和时间计数器
count.clear();
fireTimestamp.clear();
return TriggerResult.FIRE;
}
return TriggerResult.CONTINUE;
} @Override
public void clear(W window, TriggerContext ctx) throws Exception {
ctx.getPartitionedState(countStateDesc).clear();
ctx.getPartitionedState(timeStateDesc).clear();
} // 多个slot 中的 数据合并.
@Override
public void onMerge(W window, OnMergeContext ctx) throws Exception {
super.onMerge(window, ctx);
ctx.mergePartitionedState(timeStateDesc);
ctx.mergePartitionedState(countStateDesc);
}
}

Flink 自定义触发器的更多相关文章

  1. flink 自定义触发器 定时或达到数量触发

    flink 触发器 触发器确定窗口(由窗口分配程序形成)何时准备由窗口函数处理.每个WindowAssigner都带有一个默认触发器. 如果默认触发器不适合需求,我们就需要自定义触发器. 主要方法 触 ...

  2. zabbix自定义触发器

    zabbix中监控项仅负责收集数据,而通常收集数据的目的还包括在某指标对应的数据超出合理范围时给相关人员发送告警信息,"触发器"正式 用于为监控项所收集的数据定义阈值,每一个触发器 ...

  3. Flink自定义Sink

    Flink自定义Sink Flink 自定义Sink,把socket数据流数据转换成对象写入到mysql存储. #创建Student类 public class Student { private i ...

  4. Flink 自定义source和sink,获取kafka的key,输出指定key

    --------20190905更新------- 沙雕了,可以用  JSONKeyValueDeserializationSchema,接收ObjectNode的数据,如果有key,会放在Objec ...

  5. 4、flink自定义source、sink

    一.Source 代码地址:https://gitee.com/nltxwz_xxd/abc_bigdata 1.1.flink内置数据源 1.基于文件 env.readTextFile(" ...

  6. 【Linux】Zabbix自定义触发器语法

    Zabbix触发器的语法如下: {<server>:<key>.<function>(<parameter>)}<operator>< ...

  7. zabbix自定义触发器进行监控

    给某一主机创建触发器 触发器属性,其中centos是主机名,也就是你监控的那台主机的名字,可以点击bp2,查看该主机的hostname 检测该触发器 在该主机下可以看到刚创建的触发器 最后我们给该主机 ...

  8. Flink 实现指定时长或消息条数的触发器

    Flink 中窗口是很重要的一个功能,而窗口又经常配合触发器一起使用. Flink 自带的触发器大概有: CountTrigger: 指定条数触发 ContinuousEventTimeTrigger ...

  9. Flink去重统计-基于自定义布隆过滤器

    一.背景说明 在Flink中对流数据进行去重计算是常有操作,如流量域对独立访客之类的统计,去重思路一般有三个: 基于Hashset来实现去重 数据存在内存,容量小,服务重启会丢失. 使用状态编程Val ...

随机推荐

  1. 这篇SpringBoot整合JSON的学习笔记,建议收藏起来,写的太细了

    前言 JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛. 采用完全独立于编程语言的文本格式来存储和表示数据. 简洁和清晰 ...

  2. Fruity Granulizer合成器功能简介

    本章节采用图文结合的方式给大家介绍电音编曲软件-FL Studio的插件Fruity Granulizer合成器,感兴趣的朋友可以一起沟通交流. Fruity Granulizer合成器是一个使用了粒 ...

  3. 如何用Camtasia将喜欢的视频做出复古的感觉

    不知道各位可有看老电影的习惯,我个人觉得一些老电影那种别具一格的画面感是非常吸引人的韵味,尽管其色彩不是很鲜艳,但是这种黑白的感觉,对于现在的我们,往往有着不一样的吸引力.于是,我就尝试着用Camta ...

  4. 【VUE】7.Vuex基本使用

    1. 安装Vuex npm install vuex --save 2. 导入Vuex包 import Vuex from 'vuex' Vue.use(Vuex) 3. 创建store对象 cons ...

  5. 肝了一周的 UDP 基础知识终于出来了。

    我把自己以往的文章汇总成为了 Github ,欢迎各位大佬 star https://github.com/crisxuan/bestJavaer 已提交此篇文章 运输层位于应用层和网络层之间,是 O ...

  6. 完全图的最短Hamilton路径——状压dp

    题意:给出一张含有n(n<20)个点的完全图,求从0号节点到第n-1号节点的最短Hamilton路径.Hamilton路径是指不重不漏地经过每一个点的路径. 算法进阶上的一道状压例题,复杂度为O ...

  7. D. Circle Game 题解(对称博弈)

    题目链接 题目大意 t组数据(t<=100) 给你一个半径d和步数k,你最开始在原点(0,0)每次可以让x坐标增加k,或者y坐标增加k 两人轮流走,求谁最后不能走了,谁就输了,都是最优博弈 输的 ...

  8. kafka 副本机制和容错处理 -2

    文章来源于本人的印象笔记,如出现格式问题可访问该链接查看原文 原创声明:作者:Arnold.zhao 博客园地址:https://www.cnblogs.com/zh94 副本机制 Kafka的副本机 ...

  9. TkMybatis 是什么?

    一.TkMybatis Tkmybatis 是基于 Mybatis 框架开发的一个工具,通过调用它提供的方法实现对单表的数据操作,不需要写任何 sql 语句,这极大地提高了项目开发效率. 二.怎么用? ...

  10. CentOS下搭建文件共享服务

    nfs部署以及优化 Server端配置 安装rpm服务包 yum install -y nfs-utils 创建数据挂载点 mkdir -p /data 编辑exports文件 vi /etc/exp ...