flink实战-聊一聊flink中的聚合算子

前言

今天我们主要聊聊flink中的一个接口org.apache.flink.api.common.functions.AggregateFunction,这个类可以接在window流之后,做窗口内的统计计算。

注意:除了这个接口AggregateFunction,flink中还有一个抽象类AggregateFunction:org.apache.flink.table.functions.AggregateFunction,大家不要把这个弄混淆了,接口AggregateFunction我们可以理解为flink中的一个算子,和MapFunction、FlatMapFunction等是同级别的,而抽象类AggregateFunction是用于用户自定义聚合函数的,和max、min之类的函数是同级的。

原理解析

比如我们想实现一个类似sql的功能:

select TUMBLE_START(proctime,INTERVAL '2' SECOND)  as starttime,user,count(*) from logs group by user,TUMBLE(proctime,INTERVAL '2' SECOND)

这个sql就是来统计一下每两秒钟的滑动窗口内每个人出现的次数,今天我们就以这个简单的sql的功能为例讲解一下flink的aggregate算子,其实就是我们用程序来实现这个sql的功能。

首先看一下聚合函数的接口:


@PublicEvolving
public interface AggregateFunction<IN, ACC, OUT> extends Function, Serializable {
	ACC createAccumulator();
	ACC add(IN value, ACC accumulator);
	ACC merge(ACC a, ACC b);
	OUT getResult(ACC accumulator);
}

这个接口AggregateFunction里面有4个方法,我们分别来讲解一下。

  1. AggregateFunction这个类是一个泛型类,这里面有三个参数,IN, ACC, OUT。IN就是聚合函数的输入类型,ACC是存储中间结果的类型,OUT是聚合函数的输出类型。
  2. createAccumulator
    这个方法首先要创建一个累加器,要进行一些初始化的工作,比如我们要进行count计数操作,就要给累加器一个初始值。
  3. add
    add方法就是我们要做聚合的时候的核心逻辑,比如我们做count累加,其实就是来一个数,然后就加一。
    类似上面的sql的逻辑,我们在写业务逻辑的时候,可以这么想,进入这方法数的数据都是属于某一个用户的,系统在调用这个方法之前会先进行hash分组,然后不同的用户会重复调用这个方法。所以这个函数的入参是IN类型,返回值是ACC类型
  4. merge
    因为flink是一个分布式计算框架,可能计算是分布在很多节点上同时进行的,比如上述的add操作,可能同一个用户在不同的节点上分别调用了add方法在本地节点对本地的数据进行了聚合操作,但是我们要的是整个结果,整个时候,我们就需要把每个用户各个节点上的聚合结果merge一下,整个merge方法就是做这个工作的,所以它的入参和出参的类型都是中间结果类型ACC。
  5. getResult
    这个方法就是将每个用户最后聚合的结果经过处理之后,按照OUT的类型返回,返回的结果也就是聚合函数的输出结果了。

实例讲解

自定义source

首先我们自定义source生成用户的信息

	public static class MySource implements SourceFunction<Tuple2<String,Long>>{

		private volatile boolean isRunning = true;

		String userids[] = {
				"4760858d-2bec-483c-a535-291de04b2247", "67088699-d4f4-43f2-913c-481bff8a2dc5",
				"72f7b6a8-e1a9-49b4-9a0b-770c41e01bfb", "dfa27cb6-bd94-4bc0-a90b-f7beeb9faa8b",
				"aabbaa50-72f4-495c-b3a1-70383ee9d6a4", "3218bbb9-5874-4d37-a82d-3e35e52d1702",
				"3ebfb9602ac07779||3ebfe9612a007979", "aec20d52-c2eb-4436-b121-c29ad4097f6c",
				"e7e896cd939685d7||e7e8e6c1930689d7", "a4b1e1db-55ef-4d9d-b9d2-18393c5f59ee"
		};

		@Override
		public void run(SourceContext<Tuple2<String,Long>> ctx) throws Exception{
			while (isRunning){
				Thread.sleep(10);
				String userid = userids[(int) (Math.random() * (userids.length - 1))];
				ctx.collect(Tuple2.of(userid, System.currentTimeMillis()));
			}
		}

		@Override
		public void cancel(){
			isRunning = false;
		}
	}

自定义聚合函数


	public static class CountAggregate
			implements AggregateFunction<Tuple2<String,Long>,Integer,Integer>{

		@Override
		public Integer createAccumulator(){
			return 0;
		}

		@Override
		public Integer add(Tuple2<String,Long> value, Integer accumulator){
			return ++accumulator;
		}

		@Override
		public Integer getResult(Integer accumulator){
			return accumulator;
		}

		@Override
		public Integer merge(Integer a, Integer b){
			return a + b;
		}
	}

自定义结果输出函数


	/**
	 * 这个是为了将聚合结果输出
	 */
	public static class WindowResult
			implements WindowFunction<Integer,Tuple3<String,Date,Integer>,Tuple,TimeWindow>{

		@Override
		public void apply(
				Tuple key,
				TimeWindow window,
				Iterable<Integer> input,
				Collector<Tuple3<String,Date,Integer>> out) throws Exception{

			String k = ((Tuple1<String>) key).f0;
			long windowStart = window.getStart();
			int result = input.iterator().next();
			out.collect(Tuple3.of(k, new Date(windowStart), result));

		}
	}

主流程


	final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
		DataStream<Tuple2<String,Long>> dataStream = env.addSource(new MySource());

		dataStream.keyBy(0).window(TumblingProcessingTimeWindows.of(Time.seconds(2)))
		          .aggregate(new CountAggregate(), new WindowResult()
		          ).print();

		env.execute();

完整代码请参考
https://github.com/zhangjun0x01/bigdata-examples/blob/master/flink/src/main/java/function/CustomAggregateFunctionTCase.java

欢迎关注我的公众号
在这里插入图片描述

### Flink 实战教程与实际应用案例 #### YARN 运行模式下的作业提交 Flink 支持通过 YARN 集群来运行应用程序,这种方式非常适合大规模分布式计算场景。以下是基于 YARN 的作业提交命令及其解释: ```bash root@node-1:/opt/module/flink-1.17.0# bin/flink run-application -t yarn-application -c cn.konne.un.WordCountUn lib/Flink-First-Demo-1.0-SNAPSHOT.jar ``` 此命令的核心参数如下: - `-t yarn-application` 表示以 YARN 应用程序模式运行。 - `-c cn.konne.un.WordCountUn` 指定主类路径。 - `lib/Flink-First-Demo-1.0-SNAPSHOT.jar` 是打包后的 JAR 文件位置。 这步骤展示了如何将 Flink 作业部署到 YARN 上并执行[^1]。 --- #### 日志统计实战案例 在实际业务中,日志分析是个常见的应用场景。假设需要统计用户在过去五分钟内的文件操作行为(如创建、删除、更新),可以设计个简单的流处理逻辑。输入数据可能类似于以下形式: ``` 1001,delete 1002,update 1001,create 1002,delete ``` 经过处理后,输出应为每种操作的数量汇总: ``` 1001,2 1002,2 ``` 实现该功能的关键在于利用 Flink 提供的时间窗口聚合算子。具体代码片段如下所示: ```java DataStream<String> inputStream = env.socketTextStream("localhost", 9999); inputStream .keyBy(value -> value.split(",")[0]) // 按照用户 ID 分组 .timeWindow(Time.minutes(5)) // 定义时间窗口为 5 分钟 .apply((window, values) -> { int count = (int) values.spliterator().estimateSize(); return String.format("%s,%d", window.getKey(), count); }) .print(); ``` 这段代码实现了按用户分组的日志计数,并限定在最近 5 分钟范围内完成统计[^2]。 --- #### Flink 批处理环境设置 对于批处理任务,Flink 提供了灵活的本地运行机制。开发者可以选择启动完整的 Flink 环境或者直接在 Java 集合上运行程序。以下是两种主要方式的具体说明: ##### 方式:完整 Flink 环境 如果希望模拟真实的集群环境,则可以通过 `LocalExecutionEnvironment` 启动整个框架实例。例如: ```java Configuration conf = new Configuration(); conf.setFloat(ConfigConstants.TASK_MANAGER_MEMORY_FRACTION_KEY, 0.5f); // 设置 TaskManager 内存比例 final ExecutionEnvironment env = ExecutionEnvironment.createLocalEnvironment(conf); ``` 此处配置允许调整内存分配策略以及其他性能优化选项[^3]。 ##### 方式二:轻量化集合运算 当仅需验证算法逻辑而无需考虑资源调度时,可采用更高效的 `CollectionEnvironment` 方法。它会直接作用于现有的 Java 数据结构之上,而不涉及复杂的底层组件初始化过程。样例演示如下: ```java List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); ExecutionEnvironment env = ExecutionEnvironment.createCollectionsEnvironment(); DataSet<Integer> dataSet = env.fromCollection(numbers); dataSet.map(new MapFunction<Integer, Integer>() { @Override public Integer map(Integer value) throws Exception { return value * 2; } }).print(); ``` 这种方法特别适合单元测试阶段或快速原型开发需求[^3]。 --- #### 使用 MySQL-CDC 插件构建实时同步方案 随着数据库变更捕获技术的发展,越来越多的企业倾向于借助工具自动捕捉源表的变化记录并向下游目标端推送增量更新消息。针对这领域,阿里巴巴开源项目提供了专门适配器——`flink-connector-mysql-cdc` ,其 Maven 坐标声明如下: ```xml <dependency> <groupId>com.alibaba.ververica</groupId> <artifactId>flink-connector-mysql-cdc</artifactId> <version>1.1.0</version> </dependency> ``` 集成完成后即可轻松读取 Binlog 流并将结果写入 Kafka 或其他存储介质之中[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值