【发布时间】:2019-12-06 22:25:09
【问题描述】:
以下代码在套接字上接收消息,按 1 分钟滑动 10 秒的窗口计算它们,并使用缓存的计数压缩输入。
处理是事件时间。我收到的消息包含我要用于处理的时间戳。
这接近训练练习了:https://training.ververica.com/exercises/eventTimeJoin.html
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.setParallelism(1);
// Input
SocketTextStreamFunction source = new SocketTextStreamFunction("localhost", 9092, "\n", 0);
SingleOutputStreamOperator<Tuple2<String, Long>> input = env.addSource(source)
.map(x -> {
// Eg: 123;2019-11-29T16:03:44+01:00
String[] split = x.split(";");
LocalDateTime ldt = LocalDateTime.parse(split[1], DateTimeFormatter.ISO_OFFSET_DATE_TIME);
long timestamp = ldt.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli();
return new Tuple2<>(split[0], timestamp);
});
// Assign timestamp
input = input.assignTimestampsAndWatermarks(
new BoundedOutOfOrdernessTimestampExtractor<Tuple2<String, Long>>(Time.milliseconds(100)) {
@Override
public long extractTimestamp(Tuple2<String, Long> element) {
return element.f1;
}
});
input.print("Received");
// Count the nb of input in the last minutes, sliding by 10s
SingleOutputStreamOperator<Tuple2<String, Integer>> count = input
.map(x -> new Tuple2<>(x.f0, 1))
.keyBy(0)
.timeWindow(Time.minutes(1), Time.seconds(10))
.sum(1);
count.print("Count");
// Connect the input and the count
SingleOutputStreamOperator inputWithCount = input
.keyBy(0)
.connect(count.keyBy(0))
.process(
new CoProcessFunction<Tuple2<String, Long>, Tuple2<String, Integer>, Tuple3<String, Long, Integer>>() {
private ValueState<Integer> countCache;
@Override
public void open(Configuration parameters) throws Exception {
ValueStateDescriptor<Integer> desc = new ValueStateDescriptor<>("count", Integer.class);
countCache = getRuntimeContext().getState(desc);
}
@Override
public void processElement1(Tuple2<String, Long> value, Context ctx, Collector<Tuple3<String, Long, Integer>> out) throws Exception {
Integer cached = countCache.value();
if (cached == null) {
cached = 0;
}
out.collect(new Tuple3<>(value.f0, value.f1, cached));
}
@Override
public void processElement2(Tuple2<String, Integer> value, Context ctx, Collector<Tuple3<String, Long, Integer>> out) throws Exception {
countCache.update(value.f1);
}
});
inputWithCount.print("Output");
env.execute("Test");
// I did not include the import, and I pretty-print the Map function for clarity
# Start server:
ncat -lk --broker 9092
# Check what's received:
nc localhost 9092
# I run the Flink app, and use the following command
echo "123;$(date -Iseconds)" | nc 0.0.0.0 9092 ; \
echo "123;$(date -Iseconds)" | nc 0.0.0.0 9092 ; \
sleep 20s ; \
echo "123;$(date -Iseconds)" | nc 0.0.0.0 9092
现在,当我发送 2 行时,等待 20 秒再发送另一行。我希望 2 第一个输入的计数值为 0,而第三个输入的计数值为 2。 我对第一个期望是正确的,而不是第二个。
Received> (123,1575043933000)
Received> (123,1575043933000)
Output> (123,1575043933000,0)
Output> (123,1575043933000,0)
... # 20s later
Received> (123,1575043953000)
Output> (123,1575043953000,0)
Count> (123,2)
Count> (123,2)
我本来希望在输出第三个元素之前处理计数。 我误解了活动时间吗?还是我的代码做错了什么?
【问题讨论】:
标签: apache-flink