0007-Flink原理(Flink API--Flink API调用过程)

一、整体过程

二、Environment

        创建一个执行环境,表示当前执行程序的上下文。 如果程序是独立调用的,则此方法返回本地执行环境;如果从命令行客户端调用程序以提交到集群,则此方法返回此集群的执行环境。

        也就是说,getExecutionEnvironment 会根据查询运行的方式决定返回什么样的运行环境,是最常用的一种创建执行环境的方式。 

createLocalEnvironment

        返回本地执行环境,需要在调用时指定默认的并行度。

createRemoteEnvironment

        返回集群执行环境,将 Jar 提交到远程服务器。需要在调用时指定 JobManager的 IP 和端口号,并指定要在集群中运行的 Jar 包。

三、Source

3.1 从集合读取数据

package com.zjt.apitest

import org.apache.flink.streaming.api.scala._

//定义一个样例类,温度传感器
case class SensorReading(id : String, timestamp : Long, temperature : Double )

/**
  * Created by ZhangJintao on 2020/9/26.
  */
object SourceTest {
  def main(args: Array[String]) {
    // 创建执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    // 1. 从集合中读取数据
    val dataList = List(
      SensorReading("sensor_1", 1547718199, 35.8),
      SensorReading("sensor_6", 1547718201, 15.4),
      SensorReading("sensor_7", 1547718202, 6.7),
      SensorReading("sensor_10", 1547718205, 38.1)
    )
    val stream1 = env.fromCollection(dataList)

    stream1.print()

    env.execute("source test")
  }
}

运行结果如下

3.2 从文件读取数据

package com.zjt.apitest

import org.apache.flink.streaming.api.scala._

//定义一个样例类,温度传感器
case class SensorReading(id : String, timestamp : Long, temperature : Double )

/**
  * Created by ZhangJintao on 2020/9/26.
  */
object SourceTest {
  def main(args: Array[String]) {
    // 创建执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    // 1. 从集合中读取数据
//    val dataList = List(
//      SensorReading("sensor_1", 1547718199, 35.8),
//      SensorReading("sensor_6", 1547718201, 15.4),
//      SensorReading("sensor_7", 1547718202, 6.7),
//      SensorReading("sensor_10", 1547718205, 38.1)
//    )
//    val stream1 = env.fromCollection(dataList)

    // 2.从文件中读取数据
    val inputPath = "E:\\study\\IntellijWorkspace\\FlinkTurtorial\\src\\main\\resources\\sensor.txt"
    val stream1 = env.readTextFile(inputPath)

    stream1.print()

    env.execute("source test")
  }
}

sensor.txt

sensor_1,1547718199,35.8
sensor_6,1547718201,15.4
sensor_7,1547718202,6.7
sensor_10,1547718205,38.1

运行结果如下

3.3 从Kafka中读取数据

    在pom中新增依赖

        <!--
        https://mvnrepository.com/artifact/org.apache.flink/flink-connector-kafka-0.11
        -->
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-connector-kafka-0.8_2.11</artifactId>
            <version>1.10.1</version>
        </dependency>

    注意:pom中我引入的包后缀为0.8_2.11,因为我要连接的kafka版本为0.8,scala版本为2.11.在此需要根据实际情况修改。 

    新增了Flink对kafka支持的依赖后,我们可以看到执行环境中多了一个如下方法

env.addSource()

        addSource方法实现如下

     从截图中可以看到,addSource方法接收一个SourceFunction类作为输入,返回一个数据流。我们再次点进SourceFunction看看。

    可以看到SourceFunction中有两个接口需要我们自己实现,run和cancle。顾名思义,一个是连接数据源的方法,一个是取消连接数据源的方法。

    因为我们引入了Flink对kafka的依赖,SourceFunction的实现在依赖jar中已经为我们实现了,我们拿来用即可。

    在大数据(076)Spark【Spark Streaming之Spark Streaming接收并处理Kafka数据】中我们已经有介绍启动kafka的方法,在此我默认kafka已经启动,在任意一台Kafka机器上执行下方命令创建数据源。

./bin/kafka-console-producer.sh --broker-list node1:9092,node2:9092,node3:9092 --topic sensor

    代码如下

package com.zjt.apitest

import java.util.Properties

import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.connectors.kafka.{FlinkKafkaConsumer08}

//定义一个样例类,温度传感器
case class SensorReading(id : String, timestamp : Long, temperature : Double )

/**
  * Created by ZhangJintao on 2020/9/26.
  */
object SourceTest {
  def main(args: Array[String]) {
    // 创建执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    // 1. 从集合中读取数据
//    val dataList = List(
//      SensorReading("sensor_1", 1547718199, 35.8),
//      SensorReading("sensor_6", 1547718201, 15.4),
//      SensorReading("sensor_7", 1547718202, 6.7),
//      SensorReading("sensor_10", 1547718205, 38.1)
//    )
//    val stream = env.fromCollection(dataList)

    // 2.从文件中读取数据
//    val inputPath = "E:\\study\\IntellijWorkspace\\FlinkTurtorial\\src\\main\\resources\\sensor.txt"
//    val stream = env.readTextFile(inputPath)

    // 3.从kafka中读取数据
    val props = new Properties();
    props.setProperty("zookeeper.connect", "node1:2181,node2:2181,node3:2181")
    props.setProperty("group.id", "consumer-group")
    val stream = env.addSource(new FlinkKafkaConsumer08[String]("sensor", new SimpleStringSchema(), props))

    stream.print()

    env.execute("source test")
  }
}

    运行代码如下 

    我们可以看到代码没有任何输出,这是因为我们kafka还没有发送数据,我们来到kafka客户端,发送数据如下

    在观察程序后台,如下

3.4 自定义Source

    除了以上的 source 数据来源,我们还可以自定义 source。需要做的,只是传入一个 SourceFunction 的实现就可以。

    代码如下:

package com.zjt.apitest

import java.util.Properties

import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.connectors.kafka.{FlinkKafkaConsumer08}

import scala.util.Random

//定义一个样例类,温度传感器
case class SensorReading(id : String, timestamp : Long, temperature : Double )

/**
  * Created by ZhangJintao on 2020/9/26.
  */
object SourceTest {
  def main(args: Array[String]) {
    // 创建执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    // 1. 从集合中读取数据
//    val dataList = List(
//      SensorReading("sensor_1", 1547718199, 35.8),
//      SensorReading("sensor_6", 1547718201, 15.4),
//      SensorReading("sensor_7", 1547718202, 6.7),
//      SensorReading("sensor_10", 1547718205, 38.1)
//    )
//    val stream = env.fromCollection(dataList)

    // 2.从文件中读取数据
//    val inputPath = "E:\\study\\IntellijWorkspace\\FlinkTurtorial\\src\\main\\resources\\sensor.txt"
//    val stream = env.readTextFile(inputPath)

    // 3.从kafka中读取数据
//    val props = new Properties();
//    props.setProperty("bootstrap.servers", "node1:9092,node2:9092,node3:9092")
//    props.setProperty("zookeeper.connect", "node1:2181,node2:2181,node3:2181")
//    props.setProperty("group.id", "consumer-group")
//    val stream = env.addSource(new FlinkKafkaConsumer08[String]("sensor", new SimpleStringSchema(), props))

    // 4.自定义Source
    val stream = env.addSource(new MySensorSource())

    stream.print()

    env.execute("source test")
  }

  // 自定义的SourceFunction
  class MySensorSource extends SourceFunction[SensorReading]{
    // flag: 表示数据源是否还在正常运行
    var running: Boolean = true

    override def cancel(): Unit = {
      running = false
    }

    override def run(ctx: SourceFunction.SourceContext[SensorReading]): Unit = {
      // 初始化一个随机数发生器
      val rand = new Random()
      var curTemp = 1.to(10).map(
        i => ( "sensor_" + i, 65 + rand.nextGaussian() * 20 )
      )
      while(running){
        // 更新温度值
        curTemp = curTemp.map(
          t => (t._1, t._2 + rand.nextGaussian() )
        )
        // 获取当前时间戳
        val curTime = System.currentTimeMillis()
        curTemp.foreach(
          t => ctx.collect(SensorReading(t._1, curTime, t._2))
        )
        Thread.sleep(100)
      }
    }
  }
}

    执行结果如下图:

 四、Transform

    Transform算子总体分为三类。简单转换算子(map,flatmap,filter);键控制转换算子(KeyBy,Rolling Aggregation, Reduce);多流转换算子(Split 和 和 Select, Connect 和 和 CoMap,Union).

4.1、map

    流中的元素经过map一对一转换,例如将流中的数据全部乘以2.

val streamMap = stream.map { x => x * 2 }

4.2、 flatMap

    flat有平坦的意思,和map结合起来表示把把输入的数据打平映射。 作用是可以把一个输入的数据转为0-N条数据(比如把一个单词中所有的字母拆出来)。

    例如: flatMap(List(1,2,3))(i ⇒ List(i,i))

    结果是 List(1,1,2,2,3,3),

    而 List("a b", "c d").flatMap(line ⇒ line.split(" "))

    结果是 List(a, b, c, d)。

4.3、Filter

    对每个元素进行过滤,过滤的过程使用一个filter函数进行逻辑判断。对于输入的每个元素,如果filter函数返回True,则保留,如果返回False,则丢弃。

    例如:下方代码表示将x为1的数据传递给下游算子继续处理,其余数据丢弃。

val streamFilter = stream.filter{
  x => x == 1
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值