Flink的Source----数据源

Flink的Source----数据源

flink代码分为三部分:

1、Source----数据源,读取数据

2、Transformation----转换,对数据进行处理,也就是算子

3、Sink----将数据发出去

Flink的Source分为是四大类

1、基于本地集合的 source---得出的是有界流
2、基于文件的 source---得出的是有界流
3、基于网络套接字的 source---得出的是无界流
4、自定义的 source(较难,用得比较多)

自定义的 source 常见的有 Apache kafka、Amazon Kinesis Streams、RabbitMQ、Twitter Streaming API、Apache NiFi 等,当然你也可以定义自己的 source。

前面三类原理一样,底层都是Java代码实现的
1、基于本地集合的 source---有界流

基于本地集合创建DS----env.fromCollection(List())

package com.shujia.flink.source

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

object Demo1ListSource {
  def main(args: Array[String]): Unit = {
    //创建flink环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //基于本地集合创建DS---有界流
    val listDS1: DataStream[Int] = env.fromCollection(List(1, 2, 3, 4, 5, 6, 7, 8))
    //打印
    listDS1.print()

    val listDS2: DataStream[String] = env.fromCollection(List("java,java,hadoop", "java,flink", "hadoop"))
    listDS2
      .flatMap(line => line.split(","))
      .map((_,1))
      .keyBy(_._1)
      .sum(1)
      .print()


    //启动程序(有界流的启动程序,可写可不写)
    env.execute()

  }
}

执行结果

1> 2
1> 6
2> 3
2> 7
3> 4
3> 8
4> 1
4> 5
4> (hadoop,1)
4> (hadoop,2)
4> (flink,1)
1> (java,1)
1> (java,2)
1> (java,3)

Process finished with exit code 0
2、基于文件的 source----有界流

读取文件创建DS----env.readTextFile()

package com.shujia.flink.source

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

object Demo2FileSource {
  def main(args: Array[String]): Unit = {
    //创建flink环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //读取文件创建DS----有界流
    val fileDS: DataStream[String] = env.readTextFile("data/students.txt")
    //统计班级人数
    fileDS
      .map(stu=>{
      val clazz: String = stu.split(",")(4)
      (clazz,1)
    })
      .keyBy(_._1)
      .sum(1)
      .print()

    env.execute()
  }
}

执行结果

2> (文科六班,1)
2> (文科六班,2)
2> (文科六班,3)
4> (理科六班,1)
1> (文科二班,1)
1> (文科二班,2)
2> (文科一班,1)
...
...
3> (理科四班,88)
3> (理科五班,69)
3> (理科三班,67)
3> (理科一班,77)
3> (理科四班,89)
3> (理科三班,68)
3> (理科一班,78)
3> (理科四班,90)
3> (理科五班,70)
3> (理科四班,91)

Process finished with exit code 0
3、基于网络套接字的 source---无界流

读取socket构建DS----env.socketTextStream("master", 8888)

package com.shujia.flink.source

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

object Demo3SocketSource {
  def main(args: Array[String]): Unit = {
    //创建flink环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //读取socket构建DS----无界流
    val socketDS: DataStream[String] = env.socketTextStream("master", 8888)

    socketDS.print()

    //在虚拟机中输入  nc -lk 8888

    //启动flink程序
    env.execute()
  }
}

image

4、自定义的source

读取自定义的source创建DS----env.addSource()
参数需要传入一个SourceFunction,但SourceFunction是一个接口,

所以需要传入这个接口的子类,因此需要创建一个子类来实现这个接口。

子类中需要重写这个接口的两个方法run()cancle()

  • 自定义一个Source----有界流
package com.shujia.flink.source

import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala._

object Demo4SourceFunction {
  def main(args: Array[String]): Unit = {
    //创建flink环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //读取自定义的source创建DS(参数传入SourceFunction的子类对象)
    val myDS: DataStream[Int] = env.addSource(new MySource)
    myDS.print()

    env.execute()
  }
}

//创建一个类实现接口
class MySource extends SourceFunction[Int]{ //手动指定读取数据的类型

  /**
   * run方法:用于生成数据的方法,只执行一次
   * sourceContext:用于将数据发送到下游的对象
   */
  override def run(sourceContext: SourceFunction.SourceContext[Int]): Unit = {
    sourceContext.collect(6666)
  }
  //任务被取消的时候执行,一般用于回收资源(本次暂且用不到)
  override def cancel(): Unit = {
  }
}

执行结果

3> 6666

Process finished with exit code 0
  • 自定义一个Source----无界流

在子类实现的run()方法中加入一个循环即可

package com.shujia.flink.source

import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala._

object Demo4SourceFunction {
  def main(args: Array[String]): Unit = {
    //创建flink环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment

    //读取自定义的source创建DS
    val myDS: DataStream[Int] = env.addSource(new MySource)
    myDS.print()

    env.execute()
  }
}

//创建一个类实现接口
class MySource extends SourceFunction[Int]{ //手动指定读取数据的类型

  /**
   * run方法:用于生成数据的方法,只执行一次
   * sourceContext:用于将数据发送到下游的对象
   */
  override def run(sourceContext: SourceFunction.SourceContext[Int]): Unit = {
    var i = 0
    while (true){
      i += 1
      sourceContext.collect(i)//将数据发送到下游
      Thread.sleep(100) //设置一个100ms的循环时间,让其打印的慢一点
    }
  }

  override def cancel(): Unit = {
  }
}
  • 自定义Source----读取Mysql----有界流
package com.shujia.flink.source

import com.mysql.jdbc.Driver
import org.apache.flink.streaming.api.functions.source.SourceFunction
import org.apache.flink.streaming.api.scala._

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

object Demo5MysqlSource {
  def main(args: Array[String]): Unit = {
    //创建flink环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    //读取自定义的source创建DS
    val mysqlDS: DataStream[(String, String, Int, String, String)] = env.addSource(new MysqlSource)
    mysqlDS.print()

    //启动flink程序
    env.execute()

  }
}

//创建一个类来实现SourceFunction接口,需要指定泛型
//因为本次是读取学生数据,类型有5个字段
class MysqlSource extends SourceFunction[(String,String,Int,String,String)]{

  override def run(sourceContext: SourceFunction.SourceContext[(String,String,Int,String,String)]): Unit = {
    //使用JDBC读取Mysql
    Class.forName("com.mysql.jdbc.Driver")
    //建立连接
    val con: Connection = DriverManager.getConnection("jdbc:mysql://master:3306/bigdata", "root", "123456")
    //查询数据
    val sta: PreparedStatement = con.prepareStatement("select * from student")
    //执行查询
    val resultSet: ResultSet = sta.executeQuery()
    //循环解析数据
    while (resultSet.next()){
      val id: String = resultSet.getString("id")
      val name: String = resultSet.getString("name")
      val age: Int = resultSet.getInt("age")
      val gender: String = resultSet.getString("gender")
      val clazz: String = resultSet.getString("clazz")

      //将数据发送到下游
      sourceContext.collect((id,name,age,gender,clazz))
    }
    //关闭连接
    con.close()
  }

  override def cancel(): Unit = {
  }
    
}

自定义的source的其他接口

在自定义的Source除了有SourceFunction接口,还有
RichSourceFunction接口、
ParallelSourceFunction接口、
RichParallelSourceFunction接口

SourceFunction是自定义source中最基础的,是一个单线程的source
RichSourceFunction比SourceFunction多了open()和close()方法,也是一个单线程的source

ParallelSourceFunction接口,多并行的source
RichParallelSourceFunction接口,多并行的source
posted @   阿伟宝座  阅读(1554)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示