Flink流处理API

一、Environmen

1.Flink中你可以使用StreamExecutionEnvironment.getExecutionEnvironment创建l流式程序的运行环境。
例:val env:ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
2.如果没有设置并行度,会以Flink-conf.yaml文件的配置为准,默认为1。
3.createLocalEnvironment,返回本地执行环境,需要在调用时指定并行度。
4.createRemoteEnvirometn,返回集群的运行环境,将Jar提交到远程服务器。需要在调用时指定JobManager的IP和端口号,并制定在集群中运行的Jar包。

二、DataSource

1.使用 StreamExecutionEnvironment.addSource来为你的程序添加数据源
,Flink提供好了若干实现好了的source Functions,可以通过实现SourceFunction来自定义非并行的Source或者实现parallelSourceFunction接口或者扩展RichParallelourceFunction来自定义并行的Source。
2.Flinlk在流处理上的source和批处理上的source基本一致,大致有4大类
a.基于本地集合的source(Collecion-based-source)
b.基于本地文件的source(File-based-source)-读取本地文件,即符合TextInputFormat规范的文件,并将其字符串返回
c.基于网络套接字source(Socket-based-source)-从socket读取,元素可以用分隔符切分。
d.自定义source(Custom-source)
Source容错性保证
在这里插入图片描述
3.source的案例
a.基于集合的source

import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.api.scala._
object CollectionSource {

  def main(args: Array[String]): Unit = {
    // 1. 创建流处理环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    // 设置并行度,默认和CPU的核数相同
    env.setParallelism(1)

    // 2. 指定数据源,加载本地集合
    val listDataStream: DataStream[Int] = env.fromElements(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

    // 3. 打印数据
    listDataStream.print()

    // 4. 执行任务,在批处理时,print方法是可以触发任务的,但是在流环境下,必须手动执行任务
    env.execute()
  }
}

b.基于文件的Source

package com.itheima.stream.source

import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}

object CsvSource {
  def main(args: Array[String]): Unit = {
    // 1. 获取流处理运行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    // 2. 读取文件
    val textDataStream: DataStream[String] = env.readTextFile("hdfs://node01:8020/flink/datas/score.csv")
    // 3. 打印数据
    textDataStream.print()
    // 4. 执行程序
    env.execute()
  }
}

c.基于网络套接字的source
上面两种方式都是比较固定的,如果需要源源不断的产生数据,可以使用socket方式来获取数据,通过调用socketStream()方法
示例:编写Flink程序接收socket的单词数据,并以空格进行单词拆分打印
步骤:
1.获取流处理运行环境
2.构建socket流数据源,并指定端口和IP
3.对接收到的数据以空格进行拆分
4.打印输出
5.启动执行
6.在Linux中,使用nc -lk 端口号 监听端口,并发送单词

mport org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.api.scala._

object SocketSource {

  def main(args: Array[String]): Unit = {

    //1. 创建流式环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    // 2. 构建socket数据源
    val socketDataStream: DataStream[String] = env.socketTextStream("node01", 9999)
    // 3. 数据转换,空格切分
    val mapDataStream: DataStream[String] = socketDataStream.flatMap(_.split(" "))
    // 4. 打印
    mapDataStream.print()
    // 5. 执行任务
    env.execute()
  }
}

d.使用kafka作为数据源
我们可以通过FlinkKafkaConsumer011来从kafka读取数据消息:

val topic = "test"
val properties = new Properties()
properties.setProperty("bootstrap.servers", "node01:9092")
properties.setProperty("group.id", "test")
val consumer = new FlinkKafkaConsumer011[String](topic,new SimpleStringSchema(),props)

相关的配置参考org.apache.kafka.clients.consumer.ConsumerConfig
示例:使用Flink流处理方式读取kafka 的消息

import java.util
import java.util.Properties
import org.apache.flink.api.common.serialization.SimpleStringSchema
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011
import org.apache.flink.streaming.connectors.kafka.internals.KafkaTopicPartition
import org.apache.flink.api.scala._

/**
  * 使用kafka作为flink的数据源进行读取数据
  */
object KafkaSource {
  def main(args: Array[String]): Unit = {

    // 1. env
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //2:构建kafka的请求参数
    val topic = "test"
    //创建请求的参数集合
    val props = new Properties()
    props.setProperty("bootstrap.servers","node01:9092")

    //3. 创建消费者实例
    val consumer: FlinkKafkaConsumer011[String] = new FlinkKafkaConsumer011[String](topic,new SimpleStringSchema(),props)

    //4.构建kafka数据源
    val kafkaDataStream: DataStream[String] = env.addSource(consumer)

    //5.打印数据
    kafkaDataStream.print()

    //6. 启动任务
    env.execute("StreamKafkaDemo")
  }
}

e.使用MySQL作为数据源

 <!-- 指定mysql-connector的依赖 -->
 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.38</version>
 </dependency>
import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.flink.configuration.Configuration
import org.apache.flink.streaming.api.functions.source.{RichSourceFunction, SourceFunction}
import org.apache.flink.streaming.api.scala._
// 1. 创建样例类
case class User(id: String, username: String, password: String, name: String)

object MySqlSource {

  def main(args: Array[String]): Unit = {
    // 1. env
    val env = StreamExecutionEnvironment.getExecutionEnvironment

    // 2 使用自定义Source
    val mySqlDataStream: DataStream[User] = env.addSource(new MySqlSource)

    // 3. 打印结果
    mySqlDataStream.print()

    // 4. 执行任务
    env.execute()
  }
}
//1. 自定义Source,继承自RichSourceFunction
class MySqlSource extends RichSourceFunction[User] {

  var conn: Connection = _
  var ps: PreparedStatement = _

  //2. 实现open方法
  override def open(parameters: Configuration): Unit = {
    //2.1. 加载驱动
    Class.forName("com.mysql.jdbc.Driver")
    //2.2. 创建连接
    conn = DriverManager.getConnection("jdbc:mysql:///test", "root", "123456")
    //2.3. 创建PreparedStatement
    ps = conn.prepareStatement("select id,username,password,name from user")
  }

  //3. 实现run方法
  override def run(ctx: SourceFunction.SourceContext[User]) = {

    //3.1. 执行查询
    val resultSet = ps.executeQuery()

    //3.2. 遍历查询结果,收集数据
    while (resultSet.next()) {
      var id = resultSet.getString("id")
      var username = resultSet.getString("username")
      var password = resultSet.getString("password")
      var name = resultSet.getString("name")

      ctx.collect(User(id, username, password, name))
    }
  }

  override def close(): Unit = {
    ps.close()
    conn.close()
  }

  override def cancel() = {

  }
}

三、DataStream的Transformation

**map:**将DataStream中的一个元素转换为另外一个元素。
**flatmap:**将DataStream中的一个元素转换为0…n个元素。
**filter:**过滤出一些符合条件的元素。
**mapPartition:**将一个分区中的元素转换为另一个元素。
**reduce:**可以对一个DataStream或者一个group来进行聚合计算,最终聚合成一个元素。
**reduceGroup:**可以对DataStream或者一个group进行聚合计算,最终聚合成一个元素。
在这里插入图片描述
**aggregate:**按照内置的方式进行聚合,Aggregate只用作用于元组上。
**distinct:**取除重复的数据。
**join:**使用join可以将两个DataStream。
**union:**将两个DataSet连接起来,不会去重。
reblance:Flink也会出现数据倾斜的时候,reblance会使用轮询的方式将数据均匀打散。
**hashpartition:**按照指定的key进行hash分区。
**sortPartition:**指定字段对分区中的数据进行排序。
**KeyBy:**按照指定的keyl来进行分区,类似于批处理中的groupby。可以按照指定分组的字段。
**Connect:**Connect用来将两个DataStream组装成一个ConnectStreams,他使用了两个泛型,既不要求两个DataStream的element是同一类型,这样我们可以把不同的数据组装成同一结构。
**split和select:**Split是将DataStream分成多个流,用splitstream来表示DataStream —> SplitStream。
select是获取分流后对应的数据,和split搭配使用,从split搭配使用,从SplitStream中选择一个或多个流SplitStream —> DataStream。
connect与union的区别:(1)Union之前两个流的类型必须一样,Connect可以不一样,在之后coMap中再去调整为一样的。(2)Connect只能操作两个流,Union可以操作多个。

四、支持的数据类型

1.Flink流应用程序处理的是以数据对象表示的事件流
a.需要被序列化的反序列化,以便在网络中传输他们;
b.或者从状态后端、检查点和保存点读取他们;
c.为了有效的做到这一点,Flink应用程需要明确知道所要处理的数据类型;
d.Flink适用类型信息的概念表示数据类型,并未每个数据类型生成特定的序列化器、反序列化器和比较器。
2.Flink类型提取系统
a.该系统分析函数的输入和返回类型,以自动获取类型信息,从而获得序列化器、反序列化器和比较器。
b.在某些情况下,例如lambda函数或泛型类型,需要显式的提供类型信息,才能使应用程序正常工作或提高性能。
3.Flink支持Java和Scala所有常见的数据类型。
a.基础的数据类型,Flink支持Java和Scala所有基础数据类型
b.Java和Scala元组
c.Java简单对象
d.其他,List、Map、Array、Enum

五、Flink在流处理上常见的sink

1、sink kafka
开发步骤
1.创建流处理环境
2.设置并行度
3.添加自定义MySql数据源
4.转换元组数据为字符串
5.构建FlinkKafkaProducer011
6.添加sink
7.执行任务

object DataSink_kafka {
  def main(args: Array[String]): Unit = {
    // 1. 创建流处理环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    // 2. 设置并行度
    env.setParallelism(1)
    // 3. 添加自定义MySql数据源
    val source: DataStream[(Int, String, String, String)] = env.addSource(new MySql_source)

    // 4. 转换元组数据为字符串
    val strDataStream: DataStream[String] = source.map(
      line => line._1 + line._2 + line._3 + line._4
    )

    //5. 构建FlinkKafkaProducer010
    val p: Properties = new Properties
    p.setProperty("bootstrap.servers", "node01:9092")
    val sink = new FlinkKafkaProducer011[String]("test2", new SimpleStringSchema(), p)
    // 6. 添加sink
    strDataStream.addSink(sink)
    // 7. 执行任务
    env.execute("flink-kafka-wordcount")
  }
}

2、Sink Mysql
开发步骤
1.创建流执行环境
2.准备数据
3.添加sink
构建自定义sink,继承自RichSinkFunction
重写open方法,获取Connection和PrepareStatement
重写invoke方法,执行插入操作
重写close方法,关闭连接操作
4.执行任务

import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.flink.configuration.Configuration
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}

object DataSink_MySql {
  def main(args: Array[String]): Unit = {
    //1.创建流执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    //2.准备数据
    val value: DataStream[(Int, String, String, String)] = env.fromCollection(List(
      (10, "dazhuang", "123456", "大壮"),
      (11, "erya", "123456", "二丫"),
      (12, "sanpang", "123456", "三胖")
    ))
    // 3. 添加sink
    value.addSink(new MySqlSink)
    //4.触发流执行
    env.execute()
  }
}

// 自定义落地MySql的Sink
class MySqlSink extends RichSinkFunction[(Int, String, String, String)] {

  private var connection: Connection = null
  private var ps: PreparedStatement = null

  override def open(parameters: Configuration): Unit = {
    //1:加载驱动
    Class.forName("com.mysql.jdbc.Driver")
    //2:创建连接
    connection = DriverManager.getConnection("jdbc:mysql:///test", "root", "123456")
    //3:获得执行语句
    val sql = "insert into user(id , username , password , name) values(?,?,?,?);"
    ps = connection.prepareStatement(sql)
  }

  override def invoke(value: (Int, String, String, String)): Unit = {
    try {
      //4.组装数据,执行插入操作
      ps.setInt(1, value._1)
      ps.setString(2, value._2)
      ps.setString(3, value._3)
      ps.setString(4, value._4)
      ps.executeUpdate()
    } catch {
      case e: Exception => println(e.getMessage)
    }
  }

  //关闭连接操作
  override def close(): Unit = {
    if (connection != null) {
      connection.close()
    }
    if (ps != null) {
      ps.close()
    }
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据Flink官方文档,Flink处理作业可以分为以下几类: 1. 简单式转换:这种类型的作业包括一些简单的式转换,例如map、filter、keyBy等。这些作业通常只涉及到单个数据,并且可以通过Flink的DataStream API轻松实现。 2. 式聚合:这种类型的作业通常涉及到对数据进行聚合操作,例如sum、min、max等。这些作业可以通过Flink的DataStream API和Table API实现。 3. 式连接:这种类型的作业通常涉及到将多个数据连接在一起,例如join、union等。这些作业可以通过Flink的DataStream API和Table API实现。 4. 式窗口:这种类型的作业通常涉及到对数据进行窗口操作,例如滑动窗口、会话窗口等。这些作业可以通过Flink的DataStream API和Table API实现。 5. 式迭代:这种类型的作业通常涉及到对数据进行迭代操作,例如迭代计算、迭代聚合等。这些作业可以通过Flink的DataStream API和Table API实现。 6. 式机器学习:这种类型的作业通常涉及到对数据进行机器学习操作,例如分类、聚类、回归等。这些作业可以通过Flink的DataStream API和Table API结合机器学习库实现。 7. 式图处理:这种类型的作业通常涉及到对数据进行图处理操作,例如PageRank、连通性等。这些作业可以通过Flink的Gelly库实现。 下面是一个使用Flink的DataStream API实现简单式转换的例子: ```python from pyflink.datastream import StreamExecutionEnvironment env = StreamExecutionEnvironment.get_execution_environment() data = env.from_collection([(1, 'apple'), (2, 'banana'), (3, 'orange')]) result = data.map(lambda x: (x[0], x[1].upper())) result.print() env.execute("simple-transformation") ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值