在Apache Flink中拆分和加入流

时间:2018-11-02 10:52:13

标签: scala stream apache-flink

我认为我有一个非标准的用例。我想使用filter函数将源流分成几个流:

val dataStream:DataStream[MyEvent] = ...
val s1 = dataStream.filter(...).map(...)
val s2 = dataStream.filter(...).map(...)

我也有一个时间戳提取器(传入的事件将在XML中附加一个时间戳):

env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
...

dataStream.assignTimestampsAndWatermarks(new MyTimestampExtractor)
...

class MyTimestampExtractor extends AssignerWithPunctuatedWatermarks[Elem]
{
  override def checkAndGetNextWatermark(lastElement:Elem, extractedTimestamp:Long):Watermark = new Watermark(extractedTimestamp)
  override def extractTimestamp(element:Elem, previousElementTimestamp:Long):Long = XmlOperations.getDateTime(element, "@timestamp").getMillis
}

我之所以选择这种方法,是因为我不想建立一个单一的流(val s = dataStream.filter(...).map(...).filter(...).map(...)),因为我想建立一个网络来拆分/合并任意流(例如s1 + s2-> c1 ,s1 + s3-> c2,c2 + s4-> c3,...)

现在,通过上述示例发送事件时,事件E1可能同时出现在s1和s2中。以我的理解,这意味着将相同的事件E1作为第一实例放入s1(E1a),也将第二事件放入s2(E1b)。

所以我现在要做的是将E1a和E1b重新组合成一个组合的E1,它类似于E1,既是s1和s2的转换。

我尝试过:

val c1 = s1.join(s2)
  .where(_.key).equalTo(_.key)
  .window(TumblingEventTimeWindows.of(Time.seconds(10)))
  .apply((e1a, e2b) => { printf("Got e1a and e1b"); e1a })

但是,似乎事件从未达到apply函数,我找不到原因。

我的示例出了什么问题?我的类似这样的流网络的方法/想法会起作用吗?

1 个答案:

答案 0 :(得分:1)

您是否安排了水印?使用事件时间时,仅当到达水印且将事件时间时钟提前到窗口结束时才触发窗口。您可以使用时间戳提取器/水印生成器来执行此操作;有关更多详细信息,请参见an example from the documentation

如果其中一个流有时处于空闲状态,这也可能导致问题,因为空闲流上缺少水印会阻止它连接到的任何流的水印。

根据所要执行的操作,您可能会发现使用CoProcessFunction比使用时间窗口联接更容易。看看Flink培训网站上stateful enrichmentexpiring state上的练习。