FLINK |時間|透かし| Windowsのウィンドウ

 

時間とウィンドウ

図に示すようにFLINKをストリーミングで、コンセプトは、異なる時間を必要とします。

                             

タイムイベント:イベントの時間が作成されます。これは、一般的にイベントにタイムスタンプが記載されており、例えば、各ログで取得したログデータは、タイムスタンプディスペンサーFLINKアクセスイベントによって、タイムスタンプをその生成時間を記録します。

時間摂取:データはFLINK時間を入力します。

時間処理は:各オペレータの操作時間のローカルシステム時刻に基づいて実行され、マシンに関連付けられている、デフォルトの属性は時間である処理時間。

00:00.123、到着ウィンドウ2017-11-1210のシステム時間:00:たとえば、ログ時間はFLINK 2017-11-1210入力され01.234、ログは次のとおり

2017年11月2日18:37:15.624 INFO失敗RM2に超えます

ビジネスのために、1分にログの数をカウントする障害は、最も重要な何時ですか? - イベント時刻、我々は時間のログに基づいて統計を生成したいので。

 

 透かし

  ほとんどの場合、けれども、我々はソースを流れるように、イベントストリーム処理が発生したから、知っている、オペレータ、およびミドルは時間の過程でデータの時系列の流れはオペレータ生成されたイベントに従っているだけに除外しない、ネットワークによる分散および他の理由は、スクランブルされ、その結果、いわゆる障害は、を意味しない、厳密にイベント時間は配置イベントの順序に応じたFLINKがイベントを受信したシーケンス

  したがって、この時点でのみ決定ウィンドウのイベント時刻の実行に基づいて、我々は明確にすることができない場合は、一度データがすべての場所にありますが、無期限に待つことができないかどうかを、順不同で登場するという問題があり、その後、特定のことを確保するためのメカニズムが存在しなければなりませんトリガ・ウィンドウを実行するのに必要な時間を算出した後、この特定の機構であるウォーターマーク。

  透かしイベント時間は、隠された属性データそのもので進捗状況を測定するためのメカニズム、である、データ自体は、対応するウォーターマークを運びます。

  ウォーターマークは、イベントを処理するための出ている、と注文のうち、正しい取り扱いイベントは、通常、ウォーターマークが結合ウィンドウメカニズムを達成するために

透かしデータストリームはタイムスタンプを示すために使用される以下の透かしより到達した、データ、したがって、ウィンドウはれる透かしによって実行トリガー

透かしは、我々は透かしを設定することができます遅延トリガメカニズムとして理解することができ、長い遅延時間tを、システムがチェックするたびに到着したデータは、最大maxEventTimeは、その後、イベント時刻を見つけ少ないmaxEventTimeより-トンがある場合、すべてのデータは、到着していましたウィンドウ停止時間はmaxEventTimeに等しい- T は、ウィンドウがトリガされます

                         

 

ウィンドウの概要

一般的な本当のフローは、無制限のデータをどのように処理するか、無制限のですか?することができます無制限のデータがストリーム限定されたデータセットを取得するためにセグメント化すること----有界流れを与えるために処理されます。

ストリーミングフローを計算する処理するように設計されて無制限のデータセットのデータ処理エンジンを、データセットは無限にますます魅力本質的に無制限のデータ・セットです。

ウィンドウが制限されたデータストリームが流れている、ウィンドウが無限ストリームに分割されます無制限の方法でいるが、「バケット」バケツの大きさを制限され、我々はこれらのバケットに計算処理を行うことができます。

ウィンドウは2つのカテゴリに分けることができます。

   時間窓TimeWindowローリング時間ウィンドウ(タンブリングウィンドウ)、時間ウィンドウ(スライディングウィンドウ)をスライディング、セッションの時間ウィンドウ(セッションウィンドウ)。

   ウィンドウカウントCountWindowを:に従い、指定された世代番号のウィンドウのデータ項目に関係なく、時間のウィンドウの数をスライディング、カウントウィンドウにローリング。

TimeWindow

  • ウィンドウのスクロール(タンブリングWindowsの場合)

    固定されたウィンドウのデータ長に基づいて、データスライス

    特長タイムアラインメントは、ウィンドウの長さが固定され、重なりませんこれは、スライディングウィンドウ=サイトのステップサイズです。  

      使用シナリオ:商用BI統計分析(ビジネス指標上の焦点は、このような日または週の売上高は、各期間の集計操作として、多くの場合、一定期間の指標です)。

    各ローリング・ウィンドウ分配要素は、ウィンドウが固定サイズを有するスクロール、ウィンドウの指定されたウィンドウサイズに割り当てられ、オーバーラップしないれます。例:あなたは以下のようにウィンドウを作成するために、5分のスクロールウィンドウのサイズを指定した場合:

                    

import org.apache.flink.api.java.tuple.Tuple
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala.{DataStream, KeyedStream, StreamExecutionEnvironment, WindowedStream}
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.api.scala._
object StreamEventTimeApp {
  def main(args: Array[String]): Unit = {
    //环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //声明使用eventTime;引入EventTime    从调用时刻开始给env创建的每一个stream追加时间特征
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    val dstream: DataStream[String] = env.socketTextStream("hadoop101", 7777)

    val textWithTsDStream: DataStream[(String, Long, Int)] = dstream.map { text =>
      val arr: Array[String] = text.split(" ")
      (arr(0), arr(1).toLong, 1)
    }
    // 1 告知 flink如何获取数据中的event时间戳  2 告知延迟的watermark为 3s
    val textWithEventTimeDStream: DataStream[(String, Long, Int)] = textWithTsDStream.assignTimestampsAndWatermarks(
      new BoundedOutOfOrdernessTimestampExtractor[(String, Long, Int)](Time.milliseconds(3000)) { //time别导错包了
        override def extractTimestamp(element: (String, Long, Int)): Long = {
          return element._2
        }
      }).setParallelism(1)
    //每5秒开一个窗口 统计key的个数  5秒是一个数据的时间戳为准
    val textKeyStream: KeyedStream[(String, Long, Int), Tuple] = textWithEventTimeDStream.keyBy(0)
    textKeyStream.print("textKey: ")
    //滚动窗口
    val windowStream: WindowedStream[(String, Long, Int), Tuple, TimeWindow] = textKeyStream.window(TumblingEventTimeWindows.of(Time.milliseconds(5000)))

    windowStream.sum(2).print("windows: ").setParallelism(1)

    env.execute()
  }
[kris@hadoop101 gmall]$ nc -lk 7777
abc 1000
abc 3000
abc 4000
abc 5000
abc 6000
abc 7000
abc 7500
abc 8000
abc 9000
abc 12000
abc 12999
abc 14000
abc 15000
abc 17000
abc 18000

textKey: :8> (abc,1000,1)
textKey: :8> (abc,3000,1)
textKey: :8> (abc,4000,1)
textKey: :8> (abc,5000,1)
textKey: :8> (abc,6000,1)
textKey: :8> (abc,7000,1)
textKey: :8> (abc,7500,1)
textKey: :8> (abc,8000,1)
Window: > (abc,1000,3)
textKey: :8> (abc,9000,1)
textKey: :8> (abc,12000,1)
textKey: :8> (abc,12999,1)
Window: > (abc,5000,6)
textKey: :8> (abc,14000,1)
textKey: :8> (abc,15000,1)
textKey: :8> (abc,17000,1)
textKey: :8> (abc,18000,1)
Window: > (abc,12000,3)

  滚动窗口:
  X秒开一个窗口,上例中5s开一个窗;
  上例watermark 3s

  第n次发车时间:nX+3,车上携带的[X, nX)秒内的
    如第一次车上携带 [0, 5)以内的,在第 5 + 3 = 8s时间点发车
     第二次车上携带 [5, 10)以内的,在第10 + 3 = 13s时间点发车
     第三次车上携带 [10, 15)以内的,在第15 + 3 = 18s时间点发车;

 

  • 滑动窗口(Sliding Windows)

    滑动窗口是固定窗口的更广义的一种形式,滑动窗口由固定的窗口长度和滑动间隔组成

    特点窗口长度固定,有重叠

     适用场景:对最近一个时间段内的统计(求某接口最近5min的失败率来决定是否要报警);

      灵活;连续的波浪;比如股票交易所它是最近24小时的涨跌幅度,随时往后算随时往后划;

 滑动窗口分配器将元素分配到固定长度的窗口中,与滚动窗口类似,窗口的大小由窗口大小参数来配置,另一个窗口滑动参数控制滑动窗口开始的频率。因此,滑动窗口如果滑动参数小于窗口大小的话,窗口是可以重叠的,在这种情况下元素会被分配到多个窗口中。

例如,你有10分钟的窗口和5分钟的滑动,那么每个窗口中5分钟的窗口里包含着上个10分钟产生的数据,如下图所示:

                 

 

object StreamEventTimeApp {
  def main(args: Array[String]): Unit = {
    //环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //声明使用eventTime
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    val dstream: DataStream[String] = env.socketTextStream("hadoop101", 7777)

    val textWithTsDStream: DataStream[(String, Long, Int)] = dstream.map { text =>
      val arr: Array[String] = text.split(" ")
      (arr(0), arr(1).toLong, 1)
    }
    // 1 告知 flink如何获取数据中的event时间戳  2 告知延迟的watermark
    val textWithEventTimeDStream: DataStream[(String, Long, Int)] = textWithTsDStream.assignTimestampsAndWatermarks(
      new BoundedOutOfOrdernessTimestampExtractor[(String, Long, Int)](Time.milliseconds(3000)) { //time别导错包了
        override def extractTimestamp(element: (String, Long, Int)): Long = {
          return element._2
        }
      }).setParallelism(1)
    //每5秒开一个窗口 统计key的个数  5秒是一个数据的时间戳为准
    val textKeyStream: KeyedStream[(String, Long, Int), Tuple] = textWithEventTimeDStream.keyBy(0)
    textKeyStream.print("textKey: ")
    //滚动窗口
    //val windowDStream: WindowedStream[(String, Long, Int), Tuple, TimeWindow] = textKeyStream.window(TumblingEventTimeWindows.of(Time.milliseconds(5000)))

    //滑动窗口
    val windowStream: WindowedStream[(String, Long, Int), Tuple, TimeWindow] = textKeyStream.window(SlidingEventTimeWindows.of(Time.milliseconds(5000L), Time.milliseconds(2000L)))
    windowStream.sum(2).print("windows: ").setParallelism(1)

    env.execute()
  }
}
[kris@hadoop101 gmall]$ nc -lk 7777
aaa 100
aaa 500
aaa 1000
aaa 3000
aaa 3999
abc 100
abc 1000
abc 3998
abc 3999
abc 5000
abc 8000
abc 10000

textKey: :8> (abc,100,1)
textKey: :8> (abc,1000,1)
textKey: :8> (abc,3998,1)
textKey: :8> (abc,3999,1) //窗口大小0-4999;前面这些都是在4999窗口以下的范围内,但是开车的时机是在步长+watermark=4000,但开车的时候只有100这一个在里边;步长为1
windows: > (abc,100,1)
textKey: :8> (abc,5000,1) //开车取决于时间间隔步长1s, 每隔1s发一次;第二次发车是在2s的时候,延迟3s,即5s的时候发车,但这个时候车里就只有100和1000两个;
windows: > (abc,100,2)
textKey: :8> (abc,8000,1) //一车接5s的人;8000--5000--4000--3000--(这个时候它俩已经开车走了,不要了)-2000-1000
windows: > (abc,100,2) //3000那辆车
windows: > (abc,100,4) //走的是4000那辆车--100、1000、3998、3999
windows: > (abc,100,4)//5000,走的还是100、1000、3998、3999这四个,5000应该是在下一个窗口大小的范围;
textKey: :8> (abc,10000,1) //10000-3000 ==> 7000s,到5000是走完第一个窗口大小, 6000走一辆(5999--1000);7000(发车的6999-2000)
windows: > (abc,1000,4) //6000: 1000/3998/3999/5000/
windows: > (abc,3998,3) //7000: 3998/3999/5000
窗口大小设置为5s,步长为2s,watermark为3s;
开车时间:每隔2s,例如下例4s、6s、8s、10s...
第一次开车4s, 携带[0,1);
 第二次开车6s, 携带[0,2];
第三次开车8s,携带[0, 4];
第四次开车10s,携带[2, 6]
第五次开车12s,携带[4, 8]
第六次开车14s,携带[6, 10]
[kris@hadoop101 ~]$ nc -lk 7777 abc 399 abc 800 abc 1000 abc 1800 abc 2000 abc 3000 abc 4000 abc 5000 abc 5900 abc 6000 abc 7000 abc 8000 abc 9000 abc 10000 abc 11000 abc 11800 abc 12000 abc 13000 abc 14000 ============>>> textKey: :8> (abc,399,1) textKey: :8> (abc,800,1) textKey: :8> (abc,1000,1) textKey: :8> (abc,1800,1) textKey: :8> (abc,2000,1) textKey: :8> (abc,3000,1) textKey: :8> (abc,4000,1) windows: > (abc,399,2) textKey: :8> (abc,5000,1) textKey: :8> (abc,5900,1) textKey: :8> (abc,6000,1) windows: > (abc,399,5) textKey: :8> (abc,7000,1) textKey: :8> (abc,8000,1) windows: > (abc,399,7) textKey: :8> (abc,9000,1) textKey: :8> (abc,10000,1) windows: > (abc,2000,6) textKey: :8> (abc,11000,1) textKey: :8> (abc,11800,1) textKey: :8> (abc,12000,1) windows: > (abc,4000,6) textKey: :8> (abc,13000,1) textKey: :8> (abc,14000,1) windows: > (abc,6000,5)

 

 

如果watermark = 0,窗口大小为5,步长为2s的滑动窗口:

    val textWithEventTimeDStream: DataStream[(String, Long, Int)] = textWithTsDStream.assignTimestampsAndWatermarks(
      new BoundedOutOfOrdernessTimestampExtractor[(String, Long, Int)](Time.milliseconds(0)) { //time别导错包了
        override def extractTimestamp(element: (String, Long, Int)): Long = {
          return element._2
        }
      }).setParallelism(1)
    //滑动窗口
    val windowStream: WindowedStream[(String, Long, Int), Tuple, TimeWindow] = textKeyStream.window(SlidingEventTimeWindows.of(Time.milliseconds(5000L), Time.milliseconds(2000L)))
    windowStream.sum(2).print("windows: ").setParallelism(1)

[kris@hadoop101 ~]$ nc -lk 7777
abc 299
abc 500
abc 1000
abc 2000
abc 2800
abc 3000
abc 3800
abc 4800
abc 5000
abc 6000
abc 6800
abc 7000
abc 8000
abc 8600
abc 9000
abc 9500
abc 10000

textKey: :8> (abc,299,1)
textKey: :8> (abc,500,1)
textKey: :8> (abc,1000,1) 为什么以1s为基点呢?
windows: > (abc,299,2)
textKey: :8> (abc,2000,1)
textKey: :8> (abc,2800,1)
textKey: :8> (abc,3000,1)
windows: > (abc,299,5)
textKey: :8> (abc,3800,1)
textKey: :8> (abc,4800,1)
textKey: :8> (abc,5000,1)
windows: > (abc,299,8)
textKey: :8> (abc,6000,1)
textKey: :8> (abc,6800,1)
textKey: :8> (abc,7000,1)
windows: > (abc,2000,8)
textKey: :8> (abc,8000,1)
textKey: :8> (abc,8600,1)
textKey: :8> (abc,9000,1)
windows: > (abc,4800,7)
textKey: :8> (abc,9500,1)
textKey: :8> (abc,10000,1)

 

  • 会话窗口(Session Windows)

    由一系列事件组合一个指定时间长度的timeout间隙组成,类似于web应用的session,也就是一段时间没有接收到新数据就会生成新的窗口

    特点时间无对齐

    session窗口分配器通过session活动来对元素进行分组,session窗口跟滚动窗口和滑动窗口相比,不会有重叠和固定的开始时间和结束时间的情况,相反,当它在一个固定的时间周期内不再收到元素,即非活动间隔产生,那个这个窗口就会关闭。一个session窗口通过一个session间隔来配置,这个session间隔定义了非活跃周期的长度,当这个非活跃周期产生,那么当前的session将关闭并且后续的元素将被分配到新的session窗口中去。

            

 

object StreamEventTimeApp {
  def main(args: Array[String]): Unit = {
    //环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //声明使用eventTime
    env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
    val dstream: DataStream[String] = env.socketTextStream("hadoop101", 7777)

    val textWithTsDStream: DataStream[(String, Long, Int)] = dstream.map { text =>
      val arr: Array[String] = text.split(" ")
      (arr(0), arr(1).toLong, 1)
    }
    // 1 告知 flink如何获取数据中的event时间戳  2 告知延迟的watermark
    val textWithEventTimeDStream: DataStream[(String, Long, Int)] = textWithTsDStream.assignTimestampsAndWatermarks(
      new BoundedOutOfOrdernessTimestampExtractor[(String, Long, Int)](Time.milliseconds(3000)) { //time别导错包了
        override def extractTimestamp(element: (String, Long, Int)): Long = {
          return element._2
        }
      }).setParallelism(1)
    //每5秒开一个窗口 统计key的个数  5秒是一个数据的时间戳为准
    val textKeyStream: KeyedStream[(String, Long, Int), Tuple] = textWithEventTimeDStream.keyBy(0)
    textKeyStream.print("textKey: ")
    //滚动窗口
    //val windowDStream: WindowedStream[(String, Long, Int), Tuple, TimeWindow] = textKeyStream.window(TumblingEventTimeWindows.of(Time.milliseconds(5000)))
    //滑动窗口
    //val windowStream: WindowedStream[(String, Long, Int), Tuple, TimeWindow] = textKeyStream.window(SlidingEventTimeWindows.of(Time.milliseconds(5000L), Time.milliseconds(1000L)))

   //会话窗口
    val windowStream: WindowedStream[(String, Long, Int), Tuple, TimeWindow] = textKeyStream.window(EventTimeSessionWindows.withGap(Time.milliseconds(5000L)))
    windowStream.sum(2).print("windows: ").setParallelism(1)
    env.execute()
  }
}

只能两次时间的间隔是否满足条件
在触发水位5s的基础上再加延迟3s,
[kris@hadoop101 gmall]$ nc -lk 7777
abc 1000
abc 7000
abc 10000
=======>>>
textKey: :8> (abc,1000,1)
textKey: :8> (abc,7000,1)
textKey: :8> (abc,10000,1) //在上一个基础上+延迟时间3s才会开车
windows: > (abc,1000,1)


[kris@hadoop101 gmall]$ nc -lk 7777
aaa 1000
aaa 2000
aaa 7001
aaa 9000
aaa 10000
=====>>
textKey: :5> (aaa,1000,1)
textKey: :5> (aaa,2000,1)
textKey: :5> (aaa,7001,1) //两个时间点之间相差达到鸿沟5s了,在这个基础之上再加3s才能开车;
textKey: :5> (aaa,9000,1)
textKey: :5> (aaa,10000,1)
windows: > (aaa,1000,2)

 

CountWindow

CountWindow根据窗口中相同key元素的数量来触发执行,执行时只计算元素数量达到窗口大小的key对应的结果

注意:CountWindow的window_size指的是相同Key的元素的个数,不是输入的所有元素的总数

  滚动窗口

默认的CountWindow是一个滚动窗口,只需要指定窗口大小即可,当元素数量达到窗口大小时,就会触发窗口的执行。

   滑动窗口

滑动窗口和滚动窗口的函数名是完全一致的,只是在传参数时需要传入两个参数,一个是window_size,一个是sliding_size。

下面代码中的sliding_size设置为了2,也就是说,每收到两个相同key的数据就计算一次,每一次计算的window范围是5个元素。

 

 

WindowAPI

 

 Windowall是所有数据都在一个分区上;keyBy之后是分到各个分区再window去处理

おすすめ

転載: www.cnblogs.com/shengyang17/p/11798549.html