大数据学习之Flink——11侧输出流 Side Output

1. 为什么需要Side Stream

在处理一个数据源时,往往需要 将该源中的不同类型的数据做分割处理,如果使用 filter 算子对数据源进行筛选分割的 话,势必会造成数据流的多次复制,造成不必要的性能浪费;flink 中的侧输出就是将数据 流进行分割,而不对流进行复制的一种分流机制。flink 的侧输出的另一个作用就是对延时迟到的数据进行处理,这样就可以不必丢弃迟到的数据

2. 如何使用Side Stream
  1. 要使用 Side Output 的话,首先需要做的是定义一个 OutputTag 来标识 Side Output,代表这个 Tag 是要收集哪种类型的数据,如果是要收集多种不一样类型的数据,那么你就需要定义多种OutputTag

    val failTag: OutputTag[StationLog] = new OutputTag[StationLog]("failTag")
    val busyTag: OutputTag[StationLog] = new OutputTag[StationLog]("busyTag")
    val barringTag: OutputTag[StationLog] = new OutputTag[StationLog]("barringTag")
    
  2. 然后呢,可以使用下面几种函数来处理数据,在处理数据的过程中,进行判断将不同种类型的数据存到不同的 OutputTag 中去

    1. ProcessFunction
    2. KeyedProcessFunction
    3. CoProcessFunction
    4. ProcessWindowFunction
    5. ProcessAllWindowFunction
    class CreateSideOutputStream(tag: OutputTag[StationLog]) extends ProcessFunction[StationLog, StationLog] {
        override def processElement(value: StationLog, context: ProcessFunction[StationLog, StationLog]
          #Context, out: Collector[StationLog]): Unit = {
          if(value.callType.equals("success")) {
            // 输出主流
            out.collect(value)
          } else if(value.callType.equals("fail")) {
            context.output(failTag, value)
          } else if(value.callType.equals("busy")) {
            context.output(busyTag, value)
          } else if(value.callType.equals("barringTag")) {
            context.output(barringTag, value)
          }
        }
      }
    
  3. 此时, 我们已经将不同类型的数据进行放到不同的 OutputTag 里面了,然后可以使用 getSideOutput 方法来获取不同 OutputTag 的数据

    // 得到主流
    val mainStream: DataStream[StationLog] = stream.process(new CreateSideOutputStream(notSuccessTag))
    // 得到侧流. 必须通过主流, 才能获取到侧流
    val failStream: DataStream[StationLog] = mainStream.getSideOutput(failTag).print()
    val busyStream: DataStream[StationLog] = mainStream.getSideOutput(busyTag).print()
    val barringStream: DataStream[StationLog] = mainStream.getSideOutput(barringTag).print()
    
案例
  1. 问题: 根据基站的日志,请把呼叫成功的 Stream(主流)和不成功的 Stream(侧流) 分别输出。

  2. 代码

    package com.hjf.function
    
    import com.hjf.dataSource.StationLog
    import org.apache.flink.streaming.api.functions.ProcessFunction
    import org.apache.flink.util.Collector
    
    /**
     * 把呼叫成功的Stream(主流)和不成功的Stream(侧流)分别输出
     * @author Jiang锋时刻
     * @create 2020-07-11 20:27
     */
    object TestSideOutputStream {
      import org.apache.flink.streaming.api.scala._
      // 不成功的侧流标签. 侧输出流首先需要定义一个流的标签
      val notSuccessTag: OutputTag[StationLog] = new OutputTag[StationLog]("not_success")
    
      def main(args: Array[String]): Unit = {
        val streamEnv: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
        streamEnv.setParallelism(1)
        val stream: DataStream[StationLog] = streamEnv.readTextFile(getClass.getResource("/station.log").getPath)
          .map(one => {
            val arr: Array[String] = one.split(",")
            new StationLog(arr(0).trim, arr(1).trim, arr(2).trim, arr(3).trim, arr(4).trim.toLong, arr(5).trim.toLong)
          })
    
        val mainStream: DataStream[StationLog] = stream.process(new CreateSideOutputStream(notSuccessTag))
        // 得到侧流. 必须通过主流, 才能获取到侧流
        val sideStream: DataStream[StationLog] = mainStream.getSideOutput(notSuccessTag)
    
        mainStream.print("mainStream")
        sideStream.print("sideStream")
    
        streamEnv.execute()
      }
    
      class CreateSideOutputStream(tag: OutputTag[StationLog]) extends ProcessFunction[StationLog, StationLog] {
        override def processElement(value: StationLog, context: ProcessFunction[StationLog, StationLog]
          #Context, out: Collector[StationLog]): Unit = {
          if(value.callType.equals("success")) {
            // 输出主流
            out.collect(value)
          } else {
            // 输出侧流
            context.output(tag, value)
          }
        }
      }
    }
    
    
  3. 运行结果
    大数据学习之Flink——11侧输出流 Side Output_第1张图片

你可能感兴趣的:(Flink)