Flink는 시간 창, 세션 창, 통계 창 등 다양한 창을 지원하며 기본적으로 상상할 수있는 모든 것을 실현할 수 있습니다.
시간 창 (시간 창)
가장 간단하고 가장 일반적으로 사용되는 창 형식은 시간 기반 창입니다. Flink는 세 가지 종류의 시간 창을 지원합니다.
첫 번째 : 텀블링 시간 창
롤오버 시간 창은 고정되어 있습니다. 예를 들어 1 분 시간 창이 설정되면 시간 창은 현재 1 분 내의 데이터 만 계산하고 이전 1 분 또는 다음 1 분의 데이터는 고려하지 않습니다.
시간이 정렬되고 데이터가 동시에 두 창에 표시되지 않고 겹치지 않습니다.
두 번째 : 슬라이딩 시간 창 (슬라이딩 시간 창)
이름에서 알 수 있듯이 슬라이딩 윈도우는 슬라이딩 윈도우입니다. 따라서 개념적으로 이해해야 할 두 가지 개념이 있습니다.
창 : 창의 크기를 정의해야합니다.
슬라이딩 : 창에서 슬라이딩 크기 를 정의해야하지만 이론적으로는 슬라이딩 크기가 창 크기를 초과 할 수 없습니다.
슬라이딩 창은보다 일반적인 형태의 고정 창입니다. 슬라이딩 창은 고정 된 창 길이와 슬라이딩 간격 구성
창 길이는 고정되어 있으며 겹치는 부분이있을 수 있습니다.
셋째 : 세션 창 (세션 창)
지정된 시간의 타임 아웃 간격과 결합 된 일련의 이벤트로 구성됩니다. 즉, 일정 기간 동안 새 데이터가 수신되지 않으면 새 창이 생성됩니다.
주요 기능은 다음과 같습니다. 시간이 정렬되지 않음
window() 方法接收的输入参数是一个WindowAssigner
WindowAssigner 负责将每条输入的数据分发到正确的window中
Flink提供了通用的WindowAssigner
滚动窗口(tumbling window)
滑动窗口(sliding window)
会话窗口(session window)
全局窗口(global window)
创建不同类型的窗口
滚动时间窗口(tumbling time window)
timeWindow(Time.seconds(15))
滑动时间窗口(sliding time window)
.timeWindow(Time.seconds(15),Time.seconds(5))
会话窗口(session window)
.window(EventTimeSessionWindows.withGap(Time.minutes(10))
窗口函数(window function)
window function 定义了要对窗口中收集的数据做的计算操作,可以分为两类;
增量聚合函数(incrementalggergation functions)
每条数据来了就会进行计算,保持一个简单的状态
ReduceFunction, AggregateFunction
全窗口函数(full windowfunctions)
先把窗口所有数据收集起来,等到计算的时候会遍历所有数据
ProcessWindowFunction
其他一些常用的API
.trigger()---------触发器
定义window什么时候关闭,触发计算并输出结果
.evicotr()---------移除器
定义移除某些数据的逻辑
.allowedLateness() ------允许处理迟到的数据
.sideOutputLateData() -----将迟到的数据放入侧输出流
.getSideOutput() ----获取侧输出流
이론은 아직 귀여워요 마지막 밤
파일에서 데이터 배치를 읽었다 고 가정하면 15 초마다 통계가 수집되고 창에있는 각 센서의 모든 온도의 최소값과 최소 타임 스탬프가 획득됩니다.
새 스칼라 개체 만들기 WindowTest.scala
package com.mafei.apitest
import com.mafei.sinktest.SensorReadingTest5
import org.apache.flink.api.common.functions.ReduceFunction
import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, createTypeInformation}
import org.apache.flink.streaming.api.windowing.time.Time
object WindowTest {
def main(args: Array[String]): Unit = {
//创建执行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) //以事件时间作为窗口聚合
//env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime) //以数据进入flink的时间作为窗口时间
// env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime) //以Flink实际处理时间作为窗口时间
//如果发现没有输出,那可能是因为数据太少,不到15s都处理完成了,可以换成socket或者kafka来进行测试
val inputStream = env.readTextFile("/opt/java2020_study/maven/flink1/src/main/resources/sensor.txt")
env.setParallelism(1)
inputStream.print()
//先转换成样例类类型
val dataStream = inputStream
.map(data => {
val arr = data.split(",") //按照,分割数据,获取结果
SensorReadingTest5(arr(0), arr(1).toLong, arr(2).toDouble) //生成一个传感器类的数据,参数中传toLong和toDouble是因为默认分割后是字符串类别
})
//每15秒统计一次,窗口内各传感器所有温度的最小值,以及最小的时间戳
val resultStream = dataStream
.map(data=>(data.id,data.temperature,data.timestamp))
.keyBy(_._1) //按照二元组的第一个元素(id)分组
// .window(TumblingEventTimeWindows.of(Time.seconds(15))) //滚动时间窗口
// .window(SlidingProcessingTimeWindows.of(Time.seconds(15),Time.seconds(3))) //滑动时间窗口,15秒一个窗口,每次往后划3秒
// .window(EventTimeSessionWindows.withGap(Time.seconds(15))) //会话窗口,超过15秒算下一个会话
// .countWindow(15) //滚动计数窗口
.timeWindow(Time.seconds(15)) //每15秒统计一次,滚动时间窗口
// .minBy(1) //第二个元素做最小值的统计,如果只是获取所有温度的最小值,直接用这个方法就可以了。。
.reduce((curRes,newData)=>(curRes._1, curRes._2.min(newData._2),newData._3))
resultStream.print()
env.execute()
}
}
//上面reduce代码如果用这个自定义的方式也是一样可以实现,效果是一样的
class MyReducer extends ReduceFunction[SensorReadingTest5]{
override def reduce(t: SensorReadingTest5, t1: SensorReadingTest5): SensorReadingTest5 =
SensorReadingTest5(t.id, t1.timestamp,t.temperature.min(t1.temperature))
}
sensor.txt를 준비하고 지정된 디렉토리에 배치합니다.
sensor1,1603766281,1
sensor2,1603766282,42
sensor3,1603766283,43
sensor4,1603766240,40.1
sensor4,1603766284,20
sensor4,1603766249,40.2
최종 코드의 구조와 실행 효과