Flink window 以及windowFunction

Windows

Windows是处理无限流的核心。Windows将流分成有限大小的“存储桶”,我们可以在其上应用计算。本文档重点介绍如何在Flink中执行窗口化,以及程序员如何从其提供的功能中获得最大收益。

窗口式Flink程序的一般结构如下所示。第一个片段指的是键控流,第二个片段指的是非**键控流。正如人们所看到的,唯一的区别是keyBy(…)呼吁密钥流和window(…)成为windowAll(…)非键控流。这还将用作本页面其余部分的路线图。

键控视窗

stream
.keyBy(…) <- keyed versus non-keyed windows
.window(…) <- required: “assigner”
[.trigger(…)] <- optional: “trigger” (else default trigger)
[.evictor(…)] <- optional: “evictor” (else no evictor)
[.allowedLateness(…)] <- optional: “lateness” (else zero)
[.sideOutputLateData(…)] <- optional: “output tag” (else no side output for late data)
.reduce/aggregate/fold/apply() <- required: “function”
[.getSideOutput(…)] <- optional: “output tag”

非键Windows

stream
.windowAll(…) <- required: “assigner”
[.trigger(…)] <- optional: “trigger” (else default trigger)
[.evictor(…)] <- optional: “evictor” (else no evictor)
[.allowedLateness(…)] <- optional: “lateness” (else zero)
[.sideOutputLateData(…)] <- optional: “output tag” (else no side output for late data)
.reduce/aggregate/fold/apply() <- required: “function”
[.getSideOutput(…)] <- optional: “output tag”

窗口生命周期

简而言之,一旦应属于该窗口的第一个元素到达,就会创建一个窗口,并且当时间(事件或处理时间)超过其结束时间戳加上用户指定的时间后 ,该窗口将被完全删除allowed lateness(请参阅允许的延迟)。)。Flink保证只删除基于时间的窗口,而不能删除其他类型的窗口,例如全局窗口(请参阅窗口分配器)。例如,采用基于事件时间的窗口化策略,该策略每5分钟创建一次不重叠(或翻滚)的窗口,并允许延迟1分钟,因此Flink将为12:00和之间的间隔创建一个新窗口。12:05当带有时间戳的第一个元素落入此间隔时,当水印通过12:06 时间戳时,它将删除它。

此外,每个窗口将具有Trigger(参见触发器)和一个函数(ProcessWindowFunction,ReduceFunction, AggregateFunction或FoldFunction)(见窗口功能)连接到它。该函数将包含要应用于窗口内容的计算,而则Trigger指定了在什么条件下可以将窗口视为要应用该函数的条件。触发策略可能类似于“当窗口中的元素数大于4时”或“当水印通过窗口末尾时”。触发器还可以决定在创建和删除窗口之间的任何时间清除窗口的内容。在这种情况下,清除仅是指窗口中的元素,而不是窗口元数据。这意味着仍可以将新数据添加到该窗口。

除上述内容外,您还可以指定一个Evictor(请参阅Evictors),它将在触发触发器后以及应用此功能之前和/或之后从窗口中删除元素。

在下文中,我们将对上述每个组件进行更详细的介绍。我们从上面的代码片段中的必需部分开始(请参阅Keyed vs Non- Keyed Windows,Window Assigner和 Window Function),然后再转到可选部分。

Tumbling Windows翻滚窗口

翻滚窗口分配器受让人的每个元素到指定的窗口的窗口大小。滚动窗口具有固定的大小,并且不重叠。例如,如果您指定大小为5分钟的翻滚窗口,则将评估当前窗口,并且每五分钟将启动一个新窗口,如下图所示。
在这里插入图片描述

package com.baizhi.jsy.windowProcessTime
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
object FlinkWindowProcessTumbling {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏行行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(0)
      .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
        .reduce((v1,v2)=>(v1._1,v1._2+v2._2))
        .print()
    //5.执⾏行行流计算任务
    env.execute("Tumbling Window Stream WordCount")
  }
}

时间间隔可以通过使用一个指定Time.milliseconds(x),Time.seconds(x), Time.minutes(x),等等。

如最后一个示例所示,滚动窗口分配器还采用一个可选offset 参数,该参数可用于更改窗口的对齐方式。例如,如果没有偏移,则每小时滚动窗口与epoch对齐,即您将获得诸如的窗口 1:00:00.000 - 1:59:59.999,2:00:00.000 - 2:59:59.999依此类推。如果要更改,可以提供一个偏移量。随着15分钟的偏移量,你会,例如,拿 1:15:00.000 - 2:14:59.999,2:15:00.000 - 3:14:59.999等一个重要的用例的偏移是窗口调整到比UTC-0时区等。例如,在中国,您必须指定的偏移量Time.hours(-8)。

Sliding Windows滑动窗口

该滑动窗口分配器受让人元件以固定长度的窗口。类似于滚动窗口分配器,窗口的大小由窗口大小参数配置。附加的窗口滑动参数控制滑动窗口启动的频率。因此,如果幻灯片小于窗口大小,则滑动窗口可能会重叠。在这种情况下,元素被分配给多个窗口。

例如,您可以将大小为10分钟的窗口滑动5分钟。这样,您每隔5分钟就会得到一个窗口,其中包含最近10分钟内到达的事件,如下图所示。
在这里插入图片描述

package com.baizhi.jsy.windowProcessTime
import org.apache.flink.api.common.functions.AggregateFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.assigners.{SlidingProcessingTimeWindows, TumblingProcessingTimeWindows}
import org.apache.flink.streaming.api.windowing.time.Time
object FlinkWindowProcessSliding  {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏行行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(0)
      .window(SlidingProcessingTimeWindows.of(Time.seconds(4),Time.seconds(2)))
      .aggregate(new UserDefineAggregateFunction)
        .print()
    //5.执⾏行行流计算任务
    env.execute("Tumbling Window Stream WordCount")
  }
}
class UserDefineAggregateFunction extends AggregateFunction[(String,Int),(String,Int),(String,Int)]{
  override def createAccumulator(): (String, Int) = ("",0)

  override def add(in: (String, Int), acc: (String, Int)): (String, Int) = (in._1,in._2+acc._2)

  override def getResult(acc: (String, Int)): (String, Int) = acc

  override def merge(acc: (String, Int), acc1: (String, Int)): (String, Int) = (acc._1,acc._2+acc1._2)
}

Session Windows会话窗口

在会话窗口出让方按活动的会话组中的元素。与滚动窗口和滑动窗口相比,会话窗口不重叠且没有固定的开始和结束时间。相反,当会话窗口在一定时间段内未收到元素时(即,发生不活动间隙时),它将关闭。会话窗口分配器可与静态配置会话间隙或与 会话间隙提取功能,其限定不活动周期有多长。当该时间段到期时,当前会话关闭,随后的元素被分配给新的会话窗口

package com.baizhi.jsy.windowProcessTime
import java.text.SimpleDateFormat
import org.apache.flink.api.common.functions.AggregateFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.WindowFunction
import org.apache.flink.streaming.api.windowing.assigners.{ProcessingTimeSessionWindows, SlidingProcessingTimeWindows, TumblingProcessingTimeWindows}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
object FlinkWindowProcessSession  {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏行行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(word=>(word._1))
      .window(ProcessingTimeSessionWindows.withGap(Time.seconds(5)))
      .apply(new UserDefineWindowFunction)
      .print()
    //5.执⾏行行流计算任务
    env.execute("Tumbling Window Stream WordCount")
  }
}
class UserDefineWindowFunction extends WindowFunction[(String,Int),(String,Int),String,TimeWindow]{
  override def apply(key: String,
                     window: TimeWindow,
                     input: Iterable[(String, Int)],
                     out: Collector[(String, Int)]): Unit = {
    val format = new SimpleDateFormat("HH:mm:ss")
    val start = format.format(window.getStart)
    val end = format.format(window.getEnd)
    val sum = input.map(_._2).sum
    out.collect((s"${key}\t${start}~${end}",sum))
  }
}

在这里插入图片描述
在这里插入图片描述

Global Windows全球性的窗口分配器

一个全球性的窗口分配器分配使用相同的密钥相同的单个的所有元素全局窗口。仅当您还指定自定义触发器时,此窗口方案才有用。否则,将不会执行任何计算,因为全局窗口没有可以处理聚合元素的自然终点。
在这里插入图片描述

package com.baizhi.jsy.windowProcessTime
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.WindowFunction
import org.apache.flink.streaming.api.windowing.assigners.{GlobalWindows, ProcessingTimeSessionWindows, SlidingProcessingTimeWindows, TumblingProcessingTimeWindows}
import org.apache.flink.streaming.api.windowing.triggers.CountTrigger
import org.apache.flink.streaming.api.windowing.windows.{GlobalWindow, TimeWindow}
import org.apache.flink.util.Collector
object FlinkWindowProcessGlobal   {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏行行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(word=>(word._1))
      .window(GlobalWindows.create())
      .trigger(CountTrigger.of(4))
      .apply(new UserDefineGlobalWindowFunction)
      .print()
    //5.执⾏行行流计算任务
    env.execute("Tumbling Window Stream WordCount")
  }
}
class UserDefineGlobalWindowFunction extends WindowFunction[(String,Int),(String,Int),String,GlobalWindow]{
  override def apply(key: String,
                     window: GlobalWindow,
                     input: Iterable[(String, Int)],
                     out: Collector[(String, Int)]): Unit = {
    val sum = input.map(_._2).sum
    out.collect((s"${key}",sum))
  }
}

在这里插入图片描述

Window Functions

定义窗口分配器后,我们需要指定要在每个窗口上执行的计算。这是Window Function的职责,一旦系统
确定窗口已准备好进行处理,就可以处理每个窗口的元素。

窗口函数可以是ReduceFunction,AggregateFunction,FoldFunction、ProcessWindowFunction或WindowFunction(古董)之一。其中ReduceFunction和AggregateFunction在运行效率上比ProcessWindowFunction要高,因为前俩个方法执行的是增量计算,只要有数据抵达窗口,系统就会调用ReduceFunction,AggregateFunction实现增量计算;ProcessWindowFunction在窗口触发之前会一直缓存接收数据,只有当窗口就绪的时候才会对窗口中的元素做批量计算,但是该方法可以获取窗口的元数据信息。但是可以通过将ProcessWindowFunction与ReduceFunction,AggregateFunction或FoldFunction结合使用来获得窗口元素的增量聚合以及ProcessWindowFunction接收的其他窗口元数据,从而减轻这种情况。

ReduceFunction

package com.baizhi.jsy.windowFunction
import org.apache.flink.api.common.functions.ReduceFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
object FlinkWindowProcessTumblingWithReduceFunction {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(0)
      .window(TumblingProcessingTimeWindows.of(Time.seconds(10)))
        .reduce(new UserDefineReduceFunction)
        .print()
    //5.执⾏流计算任务
    env.execute("Tumbling Window Stream WordCount")
  }
}
class UserDefineReduceFunction extends ReduceFunction[(String,Int)]{
  override def reduce(t: (String, Int), t1: (String, Int)): (String, Int) = {
    println("reduce:"+t+"\t"+t1)
    (t._1,t._2+t1._2)
  }
}

AggregateFunction

package com.baizhi.jsy.windowFunction
import org.apache.flink.api.common.functions.AggregateFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
object FlinkWindowProcessTumblingWithAggregateFunction {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(0)
      .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
        .aggregate(new UserDefineAggregateFunction)
        .print()
    //5.执⾏流计算任务
    env.execute("Aggregate Window Stream WordCount")
  }
}
class UserDefineAggregateFunction extends AggregateFunction[(String,Int),(String,Int),(String,Int)]{
  override def createAccumulator(): (String, Int) = ("",0)
  override def add(in: (String, Int), acc: (String, Int)): (String, Int) = {
    println("add"+in+"\t"+acc)
    (in._1,in._2+acc._2)
  }
  override def getResult(acc: (String, Int)): (String, Int) = acc
  override def merge(a: (String, Int), b: (String, Int)): (String, Int) = {
    println("merge"+a+"\t"+b)
    (a._1,a._2+b._2)
  }
}

ProcessWindowFunction

ProcessWindowFunction获取一个Iterable,该Iterable包含窗口的所有元素,以及一个Context对象,该对象可以访问时间和状态信息,从而使其比其他窗口函数更具灵活性。这是以性能和资源消耗为代价的,因为不能增量聚合元素,而是需要在内部对其进行缓冲,直到将窗口视为已准备好进行处理为止。

请注意,ProcessWindowFunction用于简单的聚合(例如count)效率很低。下一部分说明如何将ReduceFunction或AggregateFunction与或结合使用,以ProcessWindowFunction同时获得增量聚合和的附加信息ProcessWindowFunction。

package com.baizhi.jsy.windowFunction
import java.text.SimpleDateFormat
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
object FlinkWindowProcessTumblingWithProcessWindowFunction {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(t=>t._1)
      .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
        .process(new UserDefineProcessWindowFunction)
        .print()
    //5.执⾏流计算任务
    env.execute("Aggregate Window Stream WordCount")
  }
}
class UserDefineProcessWindowFunction extends ProcessWindowFunction[(String,Int),(String,Int),String,TimeWindow]{
  val sdf = new SimpleDateFormat("HH;mm:ss")
  override def process(key: String,
                       context: Context,
                       elements: Iterable[(String, Int)],
                       out: Collector[(String, Int)]): Unit = {
    val window = context.window//获取窗口元数据
    val start = sdf.format(window.getStart)
    val end = sdf.format(window.getEnd)
    val sum = elements.map(_._2).sum

    out.collect((key+"\t["+start+"---"+end+"]",sum))
  }
}

ProcessWindowFunction & Reduce/Aggregte/Fold

package com.baizhi.jsy.windowFunction
import java.text.SimpleDateFormat
import org.apache.flink.api.common.functions.ReduceFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
object FlinkWindowProcessTumblingWithProcessWindowFunctionAndReduceFunction {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(t=>t._1)
      .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
        .reduce(new UserDefineReduceFunction2,new UserDefineProcessWindowFunction2)
        .print()
    //5.执⾏流计算任务
    env.execute("Aggregate Window Stream WordCount")
  }
}
class UserDefineProcessWindowFunction2 extends ProcessWindowFunction[(String,Int),(String,Int),String,TimeWindow]{
  val sdf = new SimpleDateFormat("HH;mm:ss")
  override def process(key: String,
                       context: Context,
                       elements: Iterable[(String, Int)],
                       out: Collector[(String, Int)]): Unit = {
    val window = context.window//获取窗口元数据
    val start = sdf.format(window.getStart)
    val end = sdf.format(window.getEnd)
    val sum = elements.map(_._2).sum
    println("list---->"+elements.toList)

    out.collect((key+"\t["+start+"---"+end+"]",sum))
  }

}
class UserDefineReduceFunction2 extends ReduceFunction[(String,Int)]{
  override def reduce(t: (String, Int), t1: (String, Int)): (String, Int) = {
    println("reduce:"+t+"\t"+t1)
    (t._1,t._2+t1._2)
  }
}

先执行reduce再执行process

在这里插入图片描述

Using per-window state in ProcessWindowFunction

在ProcessWindowFunction中使用每个窗口状态

除了访问键控状态(如任何丰富功能所允许的那样),a ProcessWindowFunction还可以使用键控状态,该键控状态的范围仅限于该函数当前正在处理的窗口。在这种情况下,重要的是要了解每个窗口状态所指的窗口是什么。涉及不同的“窗口”:

  • 指定窗口操作时定义的窗口:这可能是1小时的翻滚窗口或2小时的滑动窗口滑动1小时。
  • 给定键的已定义窗口的实际实例:对于用户ID xyz,这可能是从12:00到13:00的时间窗口。这是基于窗口定义的,并且基于作业当前正在处理的键的数量以及事件属于哪个时隙,将有许多窗口。

每个窗口的状态与这两个中的后者相关。这意味着,如果我们处理1000个不同键的事件,并且当前所有事件的事件都落入[12:00,13:00)时间窗口,那么将有1000个窗口实例,每个实例具有各自的每个窗口状态。

调用收到的Context对象上有两种方法process()可以访问两种状态:

  • globalState(),它允许访问不在窗口范围内的键状态
  • windowState(),它允许访问也作用于窗口的键控状态

如果您预期同一窗口会多次触发,则此功能很有用,例如,对于迟到的数据有较晚的触发,或者您有进行推测性较早触发的自定义触发器时,可能会发生这种情况。在这种情况下,您将存储有关先前触发或每个窗口状态中触发次数的信息。

使用窗口状态时,清除窗口时也要清除该状态,这一点很重要。这应该在clear()方法中发生。

package com.baizhi.jsy.windowFunction
import java.text.SimpleDateFormat
import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor}
import org.apache.flink.configuration.Configuration
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.ProcessWindowFunction
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
object FlinkWindowProcessTumblingWithProcessWindowFunctionState {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(t=>t._1)
      .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
        .process(new UserDefineProcessWindowFunction3)
        .print()
    //5.执⾏流计算任务
    env.execute("Aggregate Window Stream WordCount")
  }
}
class UserDefineProcessWindowFunction3 extends ProcessWindowFunction[(String,Int),(String,Int),String,TimeWindow]{
  val sdf = new SimpleDateFormat("HH;mm:ss")
  var wvsd:ValueStateDescriptor[Int]=_
  var gvsd:ValueStateDescriptor[Int]=_

  override def open(parameters: Configuration): Unit = {
    wvsd=new ValueStateDescriptor[Int]("ws",createTypeInformation[Int])
    gvsd=new ValueStateDescriptor[Int]("gs",createTypeInformation[Int])
  }
  override def process(key: String,
                       context: Context,
                       elements: Iterable[(String, Int)],
                       out: Collector[(String, Int)]): Unit = {
    val window = context.window//获取窗口元数据
    val start = sdf.format(window.getStart)
    val end = sdf.format(window.getEnd)
    val sum = elements.map(_._2).sum

    var wvs:ValueState[Int]=context.windowState.getState(wvsd)
    var gvs:ValueState[Int]=context.globalState.getState(gvsd)
    wvs.update(wvs.value()+sum)
    gvs.update(gvs.value()+sum)
    println("Window Count\t"+wvs.value()+"\tGlobal Count\t"+gvs.value())
    out.collect((key+"\t["+start+"---"+end+"]",sum))
  }
}

在这里插入图片描述

WindowFunction (Legacy)

在某些ProcessWindowFunction可以使用a的地方,您也可以使用a WindowFunction。这是旧版本ProcessWindowFunction,提供较少的上下文信息,并且没有某些高级功能,例如每个窗口的键状态。该接口将在某个时候被弃用。

package com.baizhi.jsy.windowFunction
import java.text.SimpleDateFormat
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.scala.function.WindowFunction
import org.apache.flink.streaming.api.windowing.assigners.{ProcessingTimeSessionWindows, SlidingProcessingTimeWindows, TumblingProcessingTimeWindows}
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.util.Collector
object FlinkWindowProcessSessionWithWindowFunction  {
  def main(args: Array[String]): Unit = {
    //1.创建流计算执⾏行行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.创建DataStream - 细化
    val text = env.socketTextStream("Centos",9999)
    //3.执⾏行行DataStream的转换算⼦
    val counts = text.flatMap(line=>line.split("\\s+"))
      .map(word=>(word,1))
      .keyBy(word=>(word._1))
      .window(ProcessingTimeSessionWindows.withGap(Time.seconds(5)))
      .apply(new UserDefineWindowFunction)
      .print()
    //5.执⾏行行流计算任务
    env.execute("Tumbling Window Stream WordCount")
  }
}
class UserDefineWindowFunction extends WindowFunction[(String,Int),(String,Int),String,TimeWindow]{
  override def apply(key: String,
                     window: TimeWindow,
                     input: Iterable[(String, Int)],
                     out: Collector[(String, Int)]): Unit = {
    val format = new SimpleDateFormat("HH:mm:ss")
    val start = format.format(window.getStart)
    val end = format.format(window.getEnd)
    val sum = input.map(_._2).sum
    out.collect((s"${key}\t${start}~${end}",sum))
  }
 }
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值