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

Apache flink ApacheFlink:窗口函数和时间的开始,apache-flink,flink-streaming,Apache Flink,Flink Streaming,在WindowAssigner中,一个元素被分配给一个或多个TimeWindow实例。在滑动事件时间窗口的情况下,这发生在SlidingEventTimeWindows#assignWindows1中 如果窗口的大小=5和幻灯片=1,则将时间戳=0的元素分配到以下窗口: 窗口(开始=0,结束=5) 窗口(开始=-1,结束=4) 窗口(开始=-2,结束=3) 窗口(开始=-3,结束=2) 窗口(开始=-4,结束=1) 在一幅图片中: +-&g

WindowAssigner
中,一个元素被分配给一个或多个
TimeWindow
实例。在滑动事件时间窗口的情况下,这发生在
SlidingEventTimeWindows#assignWindows
1中

如果窗口的
大小=5
幻灯片=1
,则将
时间戳=0
的元素分配到以下窗口:

  • 窗口(开始=0,结束=5)
  • 窗口(开始=-1,结束=4)
  • 窗口(开始=-2,结束=3)
  • 窗口(开始=-3,结束=2)
  • 窗口(开始=-4,结束=1)
  • 在一幅图片中:

                                +-> 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对于第一个元素应该只有一个窗口(
    t=[4,8[窗口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个窗口内


    脚注:

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

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

    但是,您可以手动筛选在超时开始之前启动的窗口:

    val env=StreamExecutionEnvironment.getExecutionEnvironment
    环境setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    val startTime=1
    val windowLength=2
    瓦尔幻灯片=1
    val input=env.fromElements((1,1)、(2,2)、(3,3))
    .分配AscendingTimeStamps(x=>x._2)
    val加窗=输入
    .timeWindowAll(时间.毫秒(窗口长度),时间.毫秒(幻灯片))
    .apply{(窗口,iterable,收集器:收集器[Int])=>
    如果(window.getStart>=startTime){
    collector.collect(iterable.map(u._1).reduce(u+u))
    }否则{
    //丢弃早期窗口
    }
    }
    windowed.print()
    env.execute()
    
    我可能会为这个问题找到更好的解决方法。 我们的想法是将水印设置在未来足够远的地方,以便为您的窗口提供足够的数据。早期的窗口仍然存在,但它们将被丢弃

    以下是具有周期性水印[T]的赋值器的概念证明:

    `wait`是您第一个窗口的大小。 似乎工作正常,但我对弗林克的理解还不够肯定。 更新:不幸的是,它不起作用(现在我不知道为什么要这样做),在带有“早期窗口”的密钥流中总是很少有密钥。因此,最后我只是用类似以下内容过滤错误的窗口:

    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))
      })
    

    作为一种“变通方法”,这种方法目前还可以。我想这种请求并不流行:)这种解决方案甚至可能无法作为变通方法使用,因为您可能需要从流中读取
    startTime
    (如果是事件时间)。而且在您自己的
    WindowAssigner
    中似乎没有简单的方法来实现这一点,因为没有简单的方法(或者我没有找到任何方法)来存储您读取的第一个元素的时间,而分配者可以访问该方法。
    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))
      })