Flink aprende de 0 a 1-Capítulo 8 API ProcessFunction (API de bajo nivel)


El operador de conversión que aprendimos antes no puede acceder a la información de la marca de tiempo y la información del nivel del agua del evento. Esto es extremadamente importante en algunos escenarios de aplicación. Por ejemplo, los operadores de transformación de mapas como MapFunction no pueden acceder a la marca de tiempo ni a la hora del evento actual.

En base a esto, la API de DataStream proporciona una serie de operadores de conversión de bajo nivel. Puede acceder a la marca de tiempo, marca de agua y registrar eventos cronometrados. También puede generar eventos específicos, como eventos de tiempo de espera.
La función de proceso se utiliza para crear aplicaciones controladas por eventos e implementar lógica empresarial personalizada (que no se puede lograr utilizando la función de ventana anterior y el operador de conversión). Por ejemplo, FlinkSQL se implementa mediante la función de proceso.

Flink proporciona 8 funciones de proceso:

  • Función de proceso

  • KeyedProcessFunction

  • CoProcessFunction

  • ProcessJoinFunction

  • Función de proceso de emisión

  • Función KeyedBroadcastProcess

  • ProcessWindowFunction

  • ProcessAllWindowFunction

1. KeyedProcessFunction

Aquí nos centramos en la introducción KeyedProcessFunction.

KeyedProcessFunctionSolía ​​operar KeyedStream. KeyedProcessFunctionSe procesará cada elemento de la secuencia y la salida será 0, 1 o varios elementos. Todo Process Functionse heredan de la RichFunctioninterfaz, se ha open(), close()y getRuntimeContext()otros métodos. Y KeyedProcessFunction[KEY, IN, OUT]además proporciona dos métodos:

  • processElement(v: IN, ctx: Context, out: Collector[OUT]), Cada elemento de la secuencia llamará a este método y el resultado de la llamada se generará en el tipo de datos Collector. El contexto puede acceder a la marca de tiempo del elemento, la clave del elemento y el servicio de tiempo TimerService. El contexto también puede enviar los resultados a otras transmisiones (salidas laterales).
  • onTimer(timestamp: Long, ctx: OnTimerContext, out: Collector[OUT])Es una función de devolución de llamada. Se llama cuando se activa el temporizador registrado anteriormente. El parámetro timestampse establece mediante un temporizador activado por una marca de tiempo. El recopilador es una colección de resultados de salida. OnTimerContextY processElementlos parámetros de contexto para proporcionar información contextual, como un temporizador, la
    información de tiempo se activa (tiempo del evento o tiempo de procesamiento).

2. TimerService y temporizadores (temporizadores)

El objeto TimerService mantenido por Context y OnTimerContext tiene los siguientes métodos:

  • currentProcessingTime(): Long devuelve el tiempo de procesamiento actual

  • currentWatermark(): Long devuelve la marca de tiempo de la marca de agua actual.

  • registerProcessingTimeTimer(timestamp: Long): La unidad registrará el temporizador del tiempo de procesamiento de la clave actual. Cuando el tiempo de procesamiento alcanza el tiempo de temporización, se activa el temporizador.

  • registerEventTimeTimer(timestamp: Long): La unidad registrará el temporizador de tiempo de evento de la tecla actual. Cuando la marca de agua es mayor o igual que el tiempo registrado por el temporizador, el temporizador se activa para ejecutar la función de devolución de llamada.

  • deleteProcessingTimeTimer(timestamp: Long): Registra el temporizador de tiempo de procesamiento antes de la eliminación de la unidad Si no hay un temporizador con esta marca de tiempo, no se ejecutará.

  • deleteEventTimeTimer(timestamp: Long): La unidad borra el temporizador de eventos registrado anteriormente. Si no hay un temporizador con esta marca de tiempo, no se ejecutará.

Cuando se activa el temporizador, se ejecutará la función de devolución de llamada onTimer (). Tenga en cuenta que el temporizador solo se puede utilizar en transmisiones con clave.

Aquí hay un ejemplo para ilustrar cómo KeyedProcessFunction opera KeyedStream.

Requisito: monitorear el valor de temperatura del sensor de temperatura, si el valor de temperatura aumenta continuamente dentro de un segundo (tiempo de procesamiento), se emite una alarma.

strem.keyBy(_.id).process(new TempIncreaseAlertFunction)

Observe cómo se implementa TempIncreaseAlertFunction. En el programa se utiliza una variable de estado como ValueState.

package com.flink.scala

import org.apache.flink.api.common.state.{
    
    ValueState, ValueStateDescriptor}
import org.apache.flink.api.scala.typeutils.Types
import org.apache.flink.api.scala._

import org.apache.flink.streaming.api.functions.KeyedProcessFunction
import org.apache.flink.util.Collector

class TempIncreaseAlertFunction extends KeyedProcessFunction[String,SensorReading,String]{
    
    
  /**
    * 保存上一个传感器温度值
    */
  lazy val lastTemp: ValueState[Double] = getRuntimeContext.getState(new ValueStateDescriptor[Double]("lastTemp",Types.of[Double]))

  /**
    * 保存注册的定时器的时间戳
    */
  lazy val currentTime : ValueState[Long] = getRuntimeContext.getState(new ValueStateDescriptor[Long]("currentTime",Types.of[Long]))
  override def processElement(r: SensorReading, context: KeyedProcessFunction[String, SensorReading, String]#Context, out: Collector[String]): Unit = {
    
    
    // 取出上一次的温度
    val prevTemp = lastTemp.value();

    // 将当前温度更新到上一次的温度这个变量中
    lastTemp.update(r.temperature)

    // 获取定时器
    val curTimerTimestamp = currentTime.value()

    // 温度下降或者是第一个温度值,删除定时器
    if (prevTemp == 0.0 || r.temperature < prevTemp) {
    
    
      context.timerService().deleteProcessingTimeTimer(curTimerTimestamp)
      // 清空定时器状态变量
      currentTime.clear()
    } else if (r.temperature > prevTemp && curTimerTimestamp == 0) {
    
    
      // 温度上升且没有设置定时器
      val timeTs = context.timerService().currentProcessingTime() + 1000
      context.timerService().registerProcessingTimeTimer(timeTs)
      currentTime.update(timeTs)
    }
  }

  override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[String, SensorReading, String]#OnTimerContext, out: Collector[String]): Unit = {
    
    
    out.collect("传感器ID为:"+ctx.getCurrentKey + "的传感器温度值已经连续1s上升了。")
    currentTime.clear()
  }
}

3. Salida lateral (SideOutput)

La salida de la mayoría de los operadores de la API DataStream es una salida única, que es un flujo de un determinado tipo de datos. A excepción del operador de división, una secuencia se puede dividir en varias secuencias y los tipos de datos de estas secuencias también son los mismos. La función de salidas laterales de la función de proceso puede generar múltiples flujos y los tipos de datos de estos flujos pueden ser diferentes. Una salida lateral se puede definir como OutputTag[X]un objeto, Xel tipo de datos del flujo de salida. La función de proceso puede emitir un evento a una o más salidas laterales a través del objeto Contexto.

Aquí hay un programa de muestra:

val monitoredReadings: DataStream[SensorReading] = strem.process(new FreezingMonitor)
monitoredReadings.getSideOutput(new OutputTag[String]("freezing-alarms")).print("side output:::")

A continuación, nos damos cuenta de FreezingMonitorla función, un sensor utilizado para controlar la temperatura, la temperatura más baja que la temperatura de 32F a la salida del lado de salida.

package com.flink.scala

import org.apache.flink.streaming.api.functions.ProcessFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.util.Collector

class FreezingMonitor extends ProcessFunction[SensorReading,SensorReading] {
    
    
  /**
    * 定义一个侧输出标签
    */
  lazy val freeZingAlarmOutput: OutputTag[String] = new OutputTag[String]("freezing-alarms")


  override def processElement(r: SensorReading, context: ProcessFunction[SensorReading, SensorReading]#Context, collector: Collector[SensorReading]): Unit = {
    
    
    // 温度在 32F 以下时,输出警告信息
    if (r.temperature < 32.0) {
    
    
      context.output(freeZingAlarmOutput,s"Freezing Alarm for ${r.id}")
    }
    // 所有数据直接常规输出到主流
    collector.collect(r)
  }
}

4. CoProcessFunction

Para dos flujos de entrada, la API de DataStream proporciona operaciones de bajo nivel como CoProcessFunction. CoProcessFunction proporciona métodos para manipular cada flujo de entrada: processElement1()y processElement2().

Al igual que ProcessFunction, ambos métodos se llaman a través del objeto Context. Este objeto de contexto puede acceder a datos de eventos, marca de tiempo del temporizador, TimerService y salidas laterales. CoProcessFunction también proporciona la onTimer()función de devolución de llamada.

Supongo que te gusta

Origin blog.csdn.net/dwjf321/article/details/109069061
Recomendado
Clasificación