Apache flink 如何在没有水印的情况下对flink的联合数据流进行排序

Apache flink 如何在没有水印的情况下对flink的联合数据流进行排序,apache-flink,Apache Flink,flink流有多个数据流,然后我将这些数据流与org.apache.flink.streaming.api.datastream.datastream#union方法合并。 然后,我得到的问题,数据流是无序的,我不能设置窗口排序数据流中的数据 我得到了答案,但是com.liam.learn.flink.example.union.UnionStreamDemo.SortFunction#onTimer 从未被调用过 环境信息:flink 1.7.0版 一般来说,我希望在没有水印的情况下对uni

flink流有多个数据流,然后我将这些数据流与org.apache.flink.streaming.api.datastream.datastream#union方法合并。 然后,我得到的问题,数据流是无序的,我不能设置窗口排序数据流中的数据

我得到了答案,但是com.liam.learn.flink.example.union.UnionStreamDemo.SortFunction#onTimer 从未被调用过

环境信息:flink 1.7.0版


一般来说,我希望在没有水印的情况下对union数据流进行排序。

您需要水印,以便排序函数知道何时可以安全地发出已排序的元素。在没有水印的情况下,从流B获得的记录的日期比流A的前N条记录的日期早,对吗

但是,特别是如果您知道任何一个流的“事件时间”都在严格地增加。下面是我写的一些代码,它扩展了David Anderson在回答上面提到的另一个问题时所发布的内容,希望这能帮助您开始

--肯

package com.scaleunlimited.flinksnippets;
导入java.util.PriorityQueue;
导入java.util.Random;
导入org.apache.flink.api.common.state.ValueState;
导入org.apache.flink.api.common.state.ValueStateDescriptor;
导入org.apache.flink.api.common.typeinfo.TypeHint;
导入org.apache.flink.api.common.typeinfo.TypeInformation;
导入org.apache.flink.configuration.configuration;
导入org.apache.flink.streaming.api.TimeCharacteristic;
导入org.apache.flink.streaming.api.TimerService;
导入org.apache.flink.streaming.api.datastream.datastream;
导入org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
导入org.apache.flink.streaming.api.functions.KeyedProcessFunction;
导入org.apache.flink.streaming.api.functions.source.RichParallelSourceFunction;
导入org.apache.flink.streaming.api.functions.timestamps.AscendingTimestampExtractor;
导入org.apache.flink.util.Collector;
导入org.junit.Test;
公共类MergeAndSortStreamTest{
@试验
public void testMergeAndSort()引发异常{
StreamExecutionEnvironment env=StreamExecutionEnvironment.createLocalEnvironment(2);
环境setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
DataStream streamA=env.addSource(新事件源(“A”))
.assignTimestampsAndWatermarks(新的EventsWassigner());
DataStream streamB=env.addSource(新事件源(“B”))
.assignTimestampsAndWatermarks(新的EventsWassigner());
streamA.工会(streamB)
.keyBy(r->r.getKey())
.process(新的SortByTimestampFunction())
.print();
execute();
}
私有静态类事件实现了可比较的{
私有字符串标签;
私有长时间戳;
公共事件(字符串标签、长时间戳){
_标签=标签;
_时间戳=时间戳;
}
公共字符串getLabel(){
退货标签;
}
公共void setLabel(字符串标签){
_标签=标签;
}
公共字符串getKey(){
返回“1”;
}
公共长getTimestamp(){
返回时间戳;
}
public void setTimestamp(长时间戳){
_时间戳=时间戳;
}
@凌驾
公共字符串toString(){
返回String.format(“%s@%d”,\u标签,\u时间戳);
}
@凌驾
公共int比较(事件o){
返回Long.compare(_timestamp,o._timestamp);
}
}
@抑制警告(“串行”)
私有静态类EventsWassigner扩展AscendingTimestampExtractor{
@凌驾
公共长提取AscendingTimeStamp(事件元素){
返回元素。getTimestamp();
}
}
@抑制警告(“串行”)
私有静态类SortByTimestampFunction扩展了KeyedProcessFunction{
private ValueState queueState=null;
@凌驾
公共无效打开(配置){
ValueStateDescriptor描述符=新的ValueStateDescriptor(
//州名
“已排序事件”,
//状态类型信息
TypeInformation.of(新的TypeHint(){
}));
queueState=getRuntimeContext().getState(描述符);
}
@凌驾
public void processElement(事件、上下文上下文、收集器输出)引发异常{
TimerService TimerService=context.TimerService();
long currentWatermark=timerService.currentWatermark();
System.out.format(“使用水印%d\n调用processElement”,currentWatermark);
if(context.timestamp()>currentWatermark){
PriorityQueue=queueState.value();
if(队列==null){
队列=新的优先级队列(10);
}
添加(事件);
queueState.update(队列);
timerService.registereventtimeter(event.getTimestamp());
}
}
@凌驾
公共void onTimer(长时间戳、OnTimerContext上下文、收集器输出)引发异常{
PriorityQueue=queueState.value();
长水印=context.timerService().currentWatermark();
System.out.format(“使用水印%d\n调用onTimer”,水印);
事件头=queue.peek();
while(head!=null&&head.getTimestamp()0){
线程。睡眠(deltaTime);
}
collect(新事件(_前缀,时间戳));
_numEvents++;
//每5…15毫秒生成一个时间戳,平均值为10。
时间戳+=(5+_rand.nextInt(10));
}
}
}
}

我假设您为每个