Flink的reduce操作是一种聚合操作,用于对数据进行分组或不分组的聚合计算,最终将数据聚合成一个元素。这个操作可以在分组的dataset上使用,也可以在不分组的dataset上使用。在分组的dataset上使用时,reduce操作应用用户定义的reduce函数将每个组减少为单个元素。对于每组输入元素,reduce函数连续地将元素对组合成一个元素,直到每个组只剩下一个元素。对于ReduceFunction,返回对象的key字段应与输入值匹配,这是因为reduce是可隐式组合的,并且从combine运算符发出的对象在传递给reduce运算符时再次按key分组。
具体来说,reduce操作适用于需要对数据进行聚合的场景,比如统计、计数等。例如,在日志分析中,可以使用reduce操作统计某个字段(如IP地址)的出现次数,或者统计某个单词在文本中出现的次数等。这种操作不仅限于分组数据,也可以直接应用于整个数据集,实现对整个数据集的聚合计算。
上图展示了reduce
算子的原理:reduce
在按照同一个Key分组的数据流上生效,它接受两个输入,生成一个输出,即两两合一地进行汇总操作,生成一个同类型的新元素。
reduce需要针对分组或者一个window(窗口)来执行,也就是分别对应于keyBy、window/timeWindow 处理后的数据,根据ReduceFunction将元素与上一个reduce后的结果合并,产出合并之后的结果
与简单聚合类似,reduce()操作也会将 KeyedStream 转换为 DataStream。它不会改变流的 元素数据类型,所以输出类型和输入类型是一样的。
调用 KeyedStream 的 reduce()方法时,需要传入一个参数,实现 ReduceFunction 接口
实例1:相邻元素求和,定义tupple2类型的元组,数据为
("flink",1 )("flink",2)("flink",3)
/**相邻元素求和,
* flink.transform.map,flink.transform.reduce flink.transform.reduce 必须和keyby结合
* 原始数据
* 1
* 2
* 3
* 组成元组
* flink.transform.map ->"flink",1 "flink",2 组成Tuple2的2元组 ("flink",1 )("flink",2)("flink",3)
* 通过keyby按照key “flink”分组,
* 通过reduce求和,对tuple2的第二列元素求和
*13> (flink,1)
* 13> (flink,3)
* 13> (flink,6)
* 13> (flink,10)
*
*/
public class Test {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> numbersString = env.socketTextStream("127.0.0.1",9999);
DataStream<Tuple2<String,Integer>> ds = numbersString.map(new MapFunction<String, Tuple2<String,Integer>>() {
@Override
public Tuple2<String, Integer> map(String s) throws Exception {
return new Tuple2<>("flink",Integer.parseInt(s));
}
}).keyBy(new KeySelector<Tuple2<String, Integer>, String>() {
@Override
public String getKey(Tuple2<String, Integer> stringIntegerTuple2) throws Exception {
return stringIntegerTuple2.f0;
}
}).reduce(new ReduceFunction<Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> reduce(Tuple2<String, Integer> stringIntegerTuple2, Tuple2<String, Integer> t1) throws Exception {
return new Tuple2<>(stringIntegerTuple2.f0,stringIntegerTuple2.f1+t1.f1);
}
});
ds.print();
env.execute("Flink Filter Example");
}
}
实例2,逗号前边的为订单id,求订单和
package flink.transform.reduce;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/**相邻元素求和,
1001,10
1002,20
1003,30
1002,30
1004,50
1001,90 对同一比金额的订单进行累加运算
先用map进行转换成tuple,再用keyBy进行分组,最后reduce 累加
*/
public class Test2 {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> numbersString = env.socketTextStream("127.0.0.1",9999);
DataStream<Tuple2<String,Integer>> td = numbersString.map(new MapFunction<String, Tuple2<String,Integer>>() {
@Override
public Tuple2<String, Integer> map(String s) throws Exception {
return new Tuple2<String,Integer>(s.split(",")[0],Integer.parseInt(s.split(",")[1]));
}
}).keyBy(0).reduce(new ReduceFunction<Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> reduce(Tuple2<String, Integer> stringIntegerTuple2, Tuple2<String, Integer> t1) throws Exception {
return new Tuple2<>(stringIntegerTuple2.f0,stringIntegerTuple2.f1+t1.f1);
}
});
td.print();
env.execute();
}
}