如何使用 Apache Flink DataStream API 输出事件对流?

How to use Apache Flink DataStream API to output stream of event pairs?

一只鞋子(一个事件)被定义为它的颜色和isLeft(如果鞋子是左腿的那么isLeft=true否则false)。

Tuple2<String, Boolean> leftBlueShoe  = Tuple2.of("blue", true);
Tuple2<String, Boolean> rightBlueShoe = Tuple2.of("blue", false);
// unbounded stream of shoes is as follows
DataStream<Tuple2<String, Boolean>> streamOfShoes = ... 
// somthing like - env.fromElements(leftBlueShoe, rightRedShoe, leftGreenShoe, rightBlueShoe, ...);

如何组成一双相同颜色的鞋子并期望匹配的鞋子立即发出,不匹配的鞋子等待它的鞋子直到window结束。

DataStream<Tuple5<String, Boolean, String, Boolean, String>> shoePairs = ...
// few events from shoePairs stream:
Tuple5<> shoePair   = Tuple5.of("blue", true, "blue", false, "pairFound");
Tuple5<> notShoePair= Tuple5.of("red", true, "red", false, "pairNotFound"); // Even if pair not found in window we tagged and kept in stream

尝试过的方法(忽略这个以避免混淆):

  1. 通过将流分成左右两部分并window连接(会产生成本吗?)

  2. 使用 TumblingProcessingTimeWindowapply() 中的自定义连接逻辑在同一流上开窗。 window 即使所有事件都配对也不会立即触发

Flink training is about finding event pairs; it's similar in spirit to what you're asking for. See the Rides and Fares Exercise 中的练习之一,它使用 RichCoFlatMapFunction 进行配对。

那里的解决方案假定完美配对始终是可能的,因此它不解决不匹配配对的情况。但是您可以找到更进一步的变体 here。此示例使用 CoProcessFunction 中的计时器来检测不匹配的对。

其他要点:

将流分成左子流和右子流的成本应该可以忽略不计。

我认为 CoGroupFunction 应该可以。如果你试过这个但它似乎没有工作,也许你正在使用事件时间 windowing 并且最后的水印丢失,阻止 window 被关闭。

更新:

查看您的代码后,我发现实现中存在问题。您的时间戳提取器使用系统时钟而不是事件中的时间戳。这会给你一些类似于(但比)使用处理时间的东西。我说 "worse than processing time" 是因为您允许事件乱序,这会增加延迟,并且它会阻止 window 关闭,直到事件充分超出 window 的结尾点到了。这意味着最后一个 window 永远不会被触发。

作为测试,尝试将时间特性切换为处理时间,删除 assignTimestampsAndWatermarks,然后查看 CoGroupFunction 是否正常工作。您也可以使用摄取时间,只要您删除水印并让 Flink 处理它(处理时间水印无关紧要;摄取时间 Flink 会为您添加水印,除非您覆盖它)。

如果您想在应用程序中使用事件时间,请在测试中使用有限源。当有限源(例如从文件或集合中读取)到达其输入的末尾时,它们会通过作业发送一个非常大的水印​​,从而关闭所有打开的 windows。