1.首先介绍一下侧输出流(SideOutPut)
大部分的 DataStream API 的算子的输出是单一输出,也就是某种数据类型的流。除了 split 算子,可以将一条流分成多条流,这些流的数据类型也都相同。process function 的 side outputs 功能可以产生多条流,并且这些流的数据类型可以不一样。一个 side output 可以定义为 OutputTag[X]对象,X 是输出流的数据类型。process function 可以通过 Context 对象发射一个事件到一个或者多个 side outputs。
2.需求的实现
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.functions.ProcessFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer
import org.apache.flink.util.Collector
import java.util.Properties
object SideOutPutTest {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
env.enableCheckpointing(1000L)
//采用kafka作为数据源
val properties = new Properties()
properties.setProperty("bootstrap.servers", "hadoop101:9092")
val data = env.addSource(new FlinkKafkaConsumer[String]("sensor",new SimpleStringSchema(),properties))
val dataStream = data.map(x => {
val arr = x.split(",")
SensorReading(arr(0).trim, arr(1).trim.toLong, arr(2).trim.toDouble)
})
val highTempStream = dataStream
.process( new SplitTempProcessor(30.0) )
highTempStream.print("high")
highTempStream.getSideOutput(new OutputTag[(String,Long,Double)]("low")).print("low")
env.execute()
}
}
class SplitTempProcessor(threshold: Double) extends ProcessFunction[SensorReading,SensorReading] {
override def processElement(value: SensorReading, ctx: ProcessFunction[SensorReading, SensorReading]#Context, out: Collector[SensorReading]): Unit = {
if(value.temperature > threshold){
//如果当前温度值大于30摄氏度输出到主流
out.collect(value)
}else{
//如果不超过10摄氏度,输出到侧输出流
ctx.output(new OutputTag[(String,Long,Double)]("low"),(value.id,value.timestamp,value.temperature))
}
}
}
3.结果展示
做一下解释,为什么high和low输出的类型不一样,是因为自定义的SplitTempProcessor在实现ProcessFunction时自定义了侧输出流的输出类型,同样也可以不定义继续采用样例类。这里采用自定义的数据类型是为了说明ProcessFunction可以实现更加复杂的业务逻辑。