1.Global Windows
全局窗口将key相同的数据都分配到一个单独的窗口中,每一种key对应一个全局窗口,多个全局窗口之间是相互独立的。如果是Non-Keyed Windows,就仅有一个全局窗口。全局窗口没有结束的边界,使用的Trigger(触发器)是NeverTrigger。如果不对全局窗口指定一个触发器,窗口是不会触发计算的
reduce/sum
public class Reduce {
/**
* Created with IntelliJ IDEA.
* Description:
* User:
* Date: 2021-01-16
* Time: 21:31
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<String> source = environment.socketTextStream("localhost", 8888);
SingleOutputStreamOperator<Integer> map = source.map(Integer::parseInt);
AllWindowedStream<Integer, GlobalWindow> windowedStream = map.countWindowAll(5);
SingleOutputStreamOperator<Integer> reduce = windowedStream.reduce(new ReduceFunction<Integer>() {
@Override
public Integer reduce(Integer t2, Integer t1) throws Exception {
return t2 + t1;
}
});
reduce.print();
environment.execute("job");
}
}
Keyby
注意lambda表达式的使用 : SingleOutputStreamOperator<Tuple2<String, Integer>> map = source.map(x -> Tuple2.of(x, 1)).returns(Types.TUPLE(Types.STRING, Types.INT));
public class Keyby {
/**
* Created with IntelliJ IDEA.
* Description:
* User:
* Date: 2021-01-16
* Time: 21:31
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<String> source = environment.socketTextStream("localhost", 8888);
SingleOutputStreamOperator<Tuple2<String, Integer>> map = source.map(x -> Tuple2.of(x, 1)).returns(Types.TUPLE(Types.STRING, Types.INT));
/* SingleOutputStreamOperator<Tuple2<String, Integer>> map = source.map(new MapFunction<String, Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> map (String s) throws Exception {
return Tuple2.of(s, 1);
}
});*/
KeyedStream<Tuple2<String, Integer>, Tuple> stream = map.keyBy(0);
// KeyedStream<Tuple2<String, Integer>, String> keyBy = map.keyBy(x -> x.f0);
WindowedStream<Tuple2<String, Integer>, Tuple, GlobalWindow> window = stream.countWindow(5);
SingleOutputStreamOperator<Tuple2<String, Integer>> reduce = window.reduce(new ReduceFunction<Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> reduce(Tuple2<String, Integer> stringIntegerTuple2, Tuple2<String, Integer> t1) throws Exception {
stringIntegerTuple2.f1 = stringIntegerTuple2.f1 + t1.f1;
return stringIntegerTuple2;
}
});
reduce.print();
environment.execute("job");
}
}
apply
public class Apply {
/**
* Created with IntelliJ IDEA.
* Description:
* User:
* Date: 2021-01-16
* Time: 22:12
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<String> source = environment.socketTextStream("localhost", 8888);
SingleOutputStreamOperator<Integer> map = source.map(Integer::parseInt);
AllWindowedStream<Integer, GlobalWindow> countWindowAll = map.countWindowAll(5);
SingleOutputStreamOperator<Integer> streamOperator = countWindowAll.apply(new AllWindowFunction<Integer, Integer, GlobalWindow>() {
@Override
public void apply(GlobalWindow window, Iterable<Integer> values, Collector<Integer> out) throws Exception {
ArrayList<Integer> list = new ArrayList<>();
for (Integer value : values) {
list.add(value);
}
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer integer, Integer t1) {
return Integer.compare(integer,t1);
}
});
for (Integer integer : list) {
out.collect(integer);
}
}
});
//.setParallelism(1) 注意在printf的后面
streamOperator.print().setParallelism(1);
environment.execute("job");
}
}
2.Tumbling Windows
滚动窗口是按照时间划分的窗口,其Assinger会将输入的每一条数据按照时间分配到固定长度的窗口内,并且按照这个固定的时间进行滚动,窗口和窗口之间没有数据重叠
TumblingWindows的of方法如果指定一个参数,就会按照指定的时间周期性的滚动形成新的窗口,例如TumblingProcessingTimeWindows.of(Time.days(1)),那么窗口的起始时间是以当前系统的ProcessingTime的整点开始以小时为单位对齐。例如[1:00:00.000, 1:59:59.999]对应一个窗口,[2:00:00.000, 2:59:59.999]会对应下一个窗口,并且会不断的生成窗口。(为了方便描述,才使用1:00:00.000这种格式,窗口的时间其实是timestamp格式)
TumblingWindows的of方法还可以传入2个参数,第二个参数的作用是将时间调整成指定时区的时间。在UTC-0以外的时区,就需要指定一个偏移量进行调整。例如,在中国就必须指定Time.hours(-8)的偏移量
Non-Keyed Tumbling Windows
public class Test1 {
/**
* Created with IntelliJ IDEA.
* Description:
* User:
* Date: 2021-01-17
* Time: 19:48
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<String> source = environment.socketTextStream("localhost", 8888);
AllWindowedStream<String, TimeWindow> stream = source.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(10)));
SingleOutputStreamOperator<String> streamOperator = stream.reduce((x, y) -> String.valueOf(Integer.parseInt(x) + Integer.parseInt(y))).returns(Types.STRING);
streamOperator.print();
environment.execute("job");
}
}
Keyed Tumbling Windows
public class Test1 {
/**
* Created with IntelliJ IDEA.
* Description:
* User:
* Date: 2021-01-17
* Time: 19:48
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<String> source = environment.socketTextStream("localhost", 8888);
SingleOutputStreamOperator<Tuple2<Integer, Integer>> operator = source.map(x -> Tuple2.of(Integer.parseInt(x), 1)).returns(Types.TUPLE(Types.INT, Types.INT));
KeyedStream<Tuple2<Integer, Integer>, Integer> keyBy = operator.keyBy(x -> x.f0);
AllWindowedStream<Tuple2<Integer, Integer>, TimeWindow> windowAll = keyBy.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(5)));
SingleOutputStreamOperator<Tuple2<Integer, Integer>> sum = windowAll.sum(1);
sum.print();
environment.execute("job");
}
}
3.Sliding Windows
滑动窗口是按照时间划分的窗口,其Assinger会将输入的每一条数据按照时间分配到固定长度的窗口内,并且还可以指定一个额外的滑动参数用来指定窗口滑动的频率(也叫滑动步长),因此当滑动步长小于窗口的长度时,窗口和窗口之间有数据重叠
SlidingWindows的of方法如果指定两个参数,第一个参数为窗口的长度,第二个为滑动的频率(或加滑动步长)。例如SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)),那么窗口的起始时间是以数据对应的EventTime并且是滑动步长的整数倍为单位对齐。例如[1:00:00.000, 1:00:09.999]对应一个窗口,[1:00:05.000, 1:00:14.999]会对应下一个窗口,两窗口有数据重叠,并且会不断的生成窗口
Non-Keyed Sliding Windows
public class Test2 {
/**
* Created with IntelliJ IDEA.
* Description:
* User:
* Date: 2021-01-17
* Time: 20:13
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<String> source = environment.socketTextStream("localhost", 8888);
SingleOutputStreamOperator<Integer> map = source.map(Integer::parseInt);
AllWindowedStream<Integer, TimeWindow> stream = map.windowAll(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)));
SingleOutputStreamOperator<Integer> sum = stream.sum(0);
sum.print();
environment.execute("job");
}
}
Keyed Sliding Windows
public class Test2 {
/**
* Created with IntelliJ IDEA.
* Description:
* User:
* Date: 2021-01-17
* Time: 20:13
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment environment = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<String> source = environment.socketTextStream("localhost", 8888);
SingleOutputStreamOperator<Tuple2<Integer, Integer>> returns = source.map(x -> Tuple2.of(Integer.parseInt(x), 1)).returns(Types.TUPLE(Types.INT, Types.INT));
KeyedStream<Tuple2<Integer, Integer>, Tuple> keyBy = returns.keyBy(0);
AllWindowedStream<Tuple2<Integer, Integer>, TimeWindow> stream = keyBy.windowAll(SlidingProcessingTimeWindows.of(Time.seconds(10), Time.seconds(5)));
SingleOutputStreamOperator<Tuple2<Integer, Integer>> sum = stream.sum(0);
sum.print();
environment.execute("job");
}
}
4.Session Windows
会话窗口是按照时间间隔划分窗口的,当超过指定的时间间隔,就会划分一个新的窗口。会话窗口没有固定的起始时间和结束时间,窗口中的数据也不会重叠。会话窗口可以指定一个固定的时间间隔,也可以根据数据中的信息传入一个函数计算出一个动态变化的时间间隔
//EventTime会话窗口wordAndOne
.keyBy(0) //指定key selector 分组字段
.window(EventTimeSessionWindows.withGap(Time.minutes(10))) //指定固定的时间间隔为10分钟
.sum(1); //触发窗口对窗口内的数据进行sum运算
wordAndOne
.keyBy(0) //指定key selector 分组字段
.window(EventTimeSessionWindows.withDynamicGap((element) -> {
return element.f1 * 1000; //指定一个动态的时间间隔,根据数据的f1字段乘以1000得到,返回的是long类型
}))
.sum(1); //触发窗口对窗口内的数据进行sum运算
//ProcessingTime会话窗口
wordAndOne
.keyBy(0) //指定key selector 分组字段
.window(ProcessingTimeSessionWindows.withGap(Time.minutes(10)))
.sum(1); //触发窗口对窗口内的数据进行sum运算
wordAndOne
.keyBy(0) //指定key selector 分组字段
.window(ProcessingTimeSessionWindows.withDynamicGap((element) -> {
return element.f1 * 1000; //指定一个动态的时间间隔,根据数据的f1字段乘以1000得到,返回的是long类型
}))
.sum(1); //触发窗口对窗口内的数据进行sum运算