Apache Flink,第二阶段在窗口流上求和

时间:2018-07-04 18:41:41

标签: scala apache-flink flink-streaming

我将Kafka事件(对应于来自设备的读数)的DataStream馈入以下代码,该代码在滑动窗口中生成每个设备的读数平均值。这很好。接下来,我要计算同一窗口中每个设备平均值的总和,这是我无法正确用句法表达的部分。

此部分有效:

val stream = env
    // words is our Kafka topic
    .addSource(kafkaConsumer)
    // configure timestamp and watermark assigner
    .assignTimestampsAndWatermarks(new DeviceTSAssigner)
      .keyBy(_.deviceIdFull)
      .timeWindow(Time.minutes(5), Time.minutes(1))
    /* count events in window */
      .apply{ (key: String, window: TimeWindow, events: Iterable[DeviceData], out: Collector[(String, Long, Double)]) =>
        out.collect( (key, window.getEnd, events.map(_.currentReading).sum/events.size))
    }

  stream.print()

输出类似于

(device1,1530681420000,0.0)
(device2,1530681420000,0.0)
(device3,1530681480000,0.0)
(device4,1530681480000,0.0)
(device5,1530681480000,52066.0)
(device6,1530681480000,69039.0)
(device7,1530681480000,79939.0)
... 
...

以下代码是我遇到的问题,我不确定该如何编码,但是我认为应该是这样的:

  val avgStream = stream
    .keyBy(2) // 2 represents the window.End from stream, see code above
    .timeWindow(Time.minutes(1)) // tumbling window
    .apply { (
               key: Long,
               window: TimeWindow,
               events: Iterable[(String, Long, Double)],
               out: Collector[(Long, Double)]) =>
      out.collect( (key, events.map( _._3 ).sum ))
    }

我在编译此代码时遇到以下错误。

Error:(70, 52) type mismatch;
 found   : (Long, org.apache.flink.streaming.api.windowing.windows.TimeWindow, Iterable[(String, Long, Double)], org.apache.flink.util.Collector[(Long, Double)]) => Unit
 required: (org.apache.flink.api.java.tuple.Tuple, org.apache.flink.streaming.api.windowing.windows.TimeWindow, Iterable[(String, Long, Double)], org.apache.flink.util.Collector[?]) => Unit
                   out: Collector[(Long, Double)]) =>

我也尝试了其他变体,例如使用AggregtionFunctions,但是无法获得过去的编译。从错误看来,我需要将输入流元素转换为元组,我已经看过一些代码,但不确定如何做到这一点。我是Scala的新手,所以我认为这是主要问题,因为我想做的事情并不复杂。

更新了07/04/2018

我认为我对我的问题有一个解决方案,似乎可以正常工作,但我仍然想保持开放态度,希望其他人可以对此进行评论(该问题以及我的解决方案)。

基本上,我删除了第一个字段(通过绘制地图),该字段是设备的名称,因为我们不需要它,然后删除了时间戳记(从上一阶段开始),将事件添加到了滚动窗口中,然后只需在第二个字段(基于索引1,从0开始)上求和即可,这是上一阶段的平均读数。

val avgStream = stream
          .map(r => (r._2, r._3))
         .keyBy(0)
         .timeWindowAll(Time.minutes(1))
         .sum(1)
         .print()

1 个答案:

答案 0 :(得分:0)

我能够回答自己的问题,因此上述方法(请参阅更新2018年7月4日)是可行的,但这是一种更好的方法(尤其是如果您不仅想在流(但多个)是使用AggregateFunction。我也早些尝试过,但是由于缺少“地图”步骤而遇到了问题。

一旦我在第二阶段映射了流以提取出感兴趣的相关字段,就可以使用AggregateFunction了。

Flink文档here和此github link都为此提供了一个示例。我从Flink文档示例开始,因为它很容易理解,然后将我的代码转换为更像github示例。