Apache Flink:窗口函数和时间的开始

时间:2016-11-17 15:13:06

标签: apache-flink flink-streaming

WindowAssigner中,元素被分配给一个或多个TimeWindow个实例。如果是滑动事件时间窗口,则会发生在SlidingEventTimeWindows#assignWindows 1 中。

如果是包含size=5slide=1的窗口,则timestamp=0的元素会被分配到以下窗口中:

  1. 窗口(开始= 0,结束= 5)
  2. 窗口(start = -1,end = 4)
  3. 窗口(开始= -2,结束= 3)
  4. 窗口(start = -3,end = 2)
  5. 窗口(start = -4,end = 1)
  6. 在一张图片中:

                                +-> Beginning of time
                                |
                                |
    +----------------------------------------------+
    |     size = 5              +--+ element       |
    |    slide = 1              |                  |
    |                           v                  |
    | t=[ 0,5[ Window 1         XXXXX              |
    | t=[-1,4[ Window 2        XXXXX               |
    | t=[-2,3[ Window 3       XXXXX                |
    | t=[-3,2[ Window 4      XXXXX                 |
    | t=[-4,1[ Window 5     XXXXX                  |
    |                                              |
    | time(-4 to +4)        ----                   |
    |                       432101234              |
    +---------------------------+------------------+
                                |
                                |
                                |
                                +
    

    有没有办法告诉Flink有一个时间的开始和之前,没有窗户?如果没有,从哪里开始寻找改变呢?在上述情况下,Flink应该只有一个窗口(t=[4,8[ Window 1)用于第一个元素。像这样:

                                +-> Beginning of time
                                |
                                |
    +-----------------------------------------------+
    |     size = 5              +--+ element        |
    |    slide = 1              |                   |
    |                           v                   |
    | t=[ 0,5[ Window 1         XXXXX               |
    | t=[ 1,6[ Window 2          XXXXX              |
    | t=[ 2,7[ Window 3           XXXXX             |
    | t=[ 3,8[ Window 4            XXXXX            |
    | t=[ 4,9[ Window 5             XXXXX           |
    |                                               |
    | time(-4 to +8)        ----                    |
    |                       4321012345678           |
    +---------------------------+-------------------+
                                |
                                |
                                |
                                +
    

    一旦窗口数达到并超过窗口大小,这将不再有效。然后,在上面的例子中,所有元素都在5个Windows中。

    脚注:

    1. org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows#assignWindows

2 个答案:

答案 0 :(得分:2)

目前无法指定Flink作业的有效时间间隔。考虑到您可能也希望将您的工作应用于历史数据,这可能也会有点问题。

但是,你可以做的是过滤手动开始时间之前开始的窗口:

val env = StreamExecutionEnvironment.getExecutionEnvironment

env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

val startTime = 1
val windowLength = 2
val slide = 1

val input = env.fromElements((1,1), (2,2), (3,3))
               .assignAscendingTimestamps(x => x._2)

val windowed = input
      .timeWindowAll(Time.milliseconds(windowLength), Time.milliseconds(slide))
      .apply{ (window, iterable, collector: Collector[Int]) =>
         if (window.getStart >= startTime) {
           collector.collect(iterable.map(_._1).reduce(_ + _))
         } else {
           // discard early windows
         }
       }

windowed.print()

env.execute()

答案 1 :(得分:0)

我可能会为此问题找到更好的解决方法。 我们的想法是将水印设置到将来足够远的地方,以便为您的窗口提供足够的数据。早期的窗户仍然存在,但它们将被丢弃。

以下是AssignerWithPeriodicWatermarks[T]的概念证明:

  class WMG[T](wait: Long) extends AssignerWithPeriodicWatermarks[T] {
    var t: Option[Long] = None
    var firstTime = true

    override def extractTimestamp(el: T, prevTs: Long): Long = {
      t = Some(prevTs)
      prevTs
    }

    override def getCurrentWatermark(): Watermark = (t, firstTime) match {
      case (None, _) => return null
      case (Some(v), false) => new Watermark(v)
      case (Some(v), true) => {
        firstTime = false
        new Watermark(v + wait)
      }
    }
  }
<德尔> `wait`是你第一个窗口的大小。 似乎工作正常,但我不明白眨眼足以确定。

更新:不幸的是,它不起作用(现在我不知道为什么会这样),键入流中的键总是很少有&#34;早期的窗口和&#34; #34 ;.所以最后我只是用以下内容过滤错误的窗口:

val s = (winSize/winStep).intValue
kstream.flatMapWithState((in: StreamOut, state: Option[Int]) =>      
  state match {
    case None    => (Seq(), Some(1))
    case Some(s) => (Seq(in), Some(s))
    case Some(v) => (Seq(), Some(v+1))
  })