程序代碼
import com.atguigu.bean.SensorReading
import com.atguigu.window.MyReduceFunc
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
object EventTimeTest {
def main(args: Array[String]): Unit = {
val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
// 從調用時刻開始給env創建的每一個stream追加時間特徵
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
// 設置watermark的默認生成周期 -> 100毫秒生成一個WaterMark
env.getConfig.setAutoWatermarkInterval(100L)
val inputDStream: DataStream[String] = env.socketTextStream("hadoop102", 7777)
val dataDstream: DataStream[SensorReading] = inputDStream
.map( data => {
val dataArray: Array[String] = data.split(",")
SensorReading(dataArray(0), dataArray(1).toLong, dataArray(2).toDouble)
})
// .assignAscendingTimestamps( _.timestamp * 1000L ) // 理想狀態下直接指定時間戳字段就可以了
.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[SensorReading]
// 給WaterMark的一個初始值延時時間
(Time.milliseconds(1000)) {
// 指定時間戳字段以秒爲單位 * 1000
override def extractTimestamp(element: SensorReading): Long = element.timestamp * 1000L
})
// 三重保證 watermark(水位線) | allowedLateness(最大遲到數據) | sideOutputLateData(側輸出流)
val resultDStream: DataStream[SensorReading] = dataDstream
.keyBy("id")
.timeWindow( Time.seconds(5) )
.allowedLateness( Time.minutes(1) )
.sideOutputLateData( new OutputTag[SensorReading]("late") )
.reduce( MyReduceFunc() )
dataDstream.print("data")
resultDStream.print("result")
// 獲取測輸出流的late並打印
resultDStream.getSideOutput( new OutputTag[SensorReading]("late") ).print("late")
env.execute("eventTime test job")
}
}
水平線watermark
窗口關閉爲5秒,watermark延時爲1秒,所以其實窗口數據只要[0,5), 5取不到(其實具體的時間戳的窗口從哪開始到那結束會有一個方法,並不是第一條數據時間戳是0就往後延長5秒,下面會看到),但是因爲watermark延長了1s 輸出到了時間戳6秒的時候纔會進行輸出,這時候窗口並沒有關閉,因爲我們設置了遲到數據allowedLateness
遲到數據allowedLateness
遲到數據設置成了一分鐘,這一分鐘之類所有的在[0,5)時間戳裏的數據都會進行輸出,來一條輸出。一分鐘後窗口才是正式關閉
側輸出流sideOutputLateData
兜底保證,窗口在關閉後,把數據輸出到側輸出流,之後看到late的數據可以進行和之前的數據進行手動合併
實際窗口時間戳程序底層算法