Flink编程三大组件(一)——Source

在这里插入图片描述

Data Source 就是数据来源。 Flink 作为一款流式计算框架,它可用来做批处理,即处理静态的数据集、历史的数据集; 也可以用来做流处理,即实时的处理些实时数据流,实时的产生数据流结果,只要数据源源不断的过来,Flink 就能够一直计算下去,这个 Data Source就是数据的来源地。 Flink 中可以使用 StreamExecutionEnvironment.addSource(sourceFunction)来为你的程序添加数据来源。 Flink 已经提供了若干实现好了的 source functions,当然也可以通过实现 SourceFunction 来 自定义非并行的 source 或者扩展 RichParallelSourceFunction 或者实现 ParallelSourceFunction 接口来自定义并行的 source。 Source:数据源,Flink 在流处理和批处理上的 source 大概有 4 类:

  • 基于本地集合的 source
  • 基于文件的 source
  • 基于网络套接字的 source
  • 自定义的 source

Maven依赖

<properties>
	<flink.version>1.7.2flink.version>
properties>
<dependencies>
	
	<dependency>
		<groupId>org.apache.flinkgroupId>
		<artifactId>flink-javaartifactId>
		<version>${flink.version}version>
	dependency>
	<dependency>
		<groupId>org.apache.flinkgroupId>
		<artifactId>flink-scala_2.11artifactId>
		<version>${flink.version}version>
	dependency>
	<dependency>
		<groupId>org.apache.flinkgroupId>
		<artifactId>flink-streaming-java_2.11artifactId>
		<version>${flink.version}version>
	dependency>
	<dependency>
		<groupId>org.apache.flinkgroupId>
		<artifactId>flink-streaming-scala_2.11artifactId>
		<version>${flink.version}version>
	dependency>
	<dependency>
		<groupId>mysqlgroupId>
		<artifactId>mysql-connector-javaartifactId>
		<version>5.1.39version>
	dependency>
dependencies>

student.txt

学号,姓名,性别,年龄,部门
95002,刘晨,女,19,IS
95017,王风娟,女,18,IS
95018,王一,女,19,IS
95013,"欧阳,少恭",男,21,CS
#古剑奇谭BOSS(测试ignoreComments)
这里是错误数据(测试lenient)
95014,王小丽,女,19,CS
95019,邢小丽,女,19,IS
95020,赵钱,男,21,IS
95003,王敏,女,22,MA
95004,张立,男,19,IS
95012,孙花,女,20,CS
95010,孔小涛,男,19,CS
95005,刘刚,男,18,MA
95006,孙庆,男,23,CS
95007,易思玲,女,19,MA
95008,李娜,女,18,CS
95021,周二,男,17,MA
95022,郑明,男,20,MA
95001,李勇,男,20,CS
95011,包小柏,男,18,MA
95009,梦圆圆,女,18,MA
95015,王君,男,18,MA
95016,黄渤,男,23,MA

文章目录

      • 1.基于集合
      • 2.基于文件
      • 3.基于 Socket
      • 4.自定义

1.基于集合

  1. fromCollection(Collection) 从 Java 的 Java.util.Collection 创建数据流。集合中的所有元素类型必须相同

  2. fromCollection(Iterator, Class) 从一个迭代器中创建数据流。Class 指定了该迭代器返回元素的类型

  3. fromElements(T„) 从给定的对象序列中创建数据流。所有对象类型必须相同

  4. fromParallelCollection(SplittableIterator, Class) 从一个迭代器中创建并行数据流。Class 指定了该迭代器返回元素的类型。

  5. generateSequence(from, to) 创建一个生成指定区间范围内的数字序列的并行数据流

    FromCollection.scala

    package blog.source
    
    import java.lang
    import org.apache.flink.api.scala.{DataSet, ExecutionEnvironment, _}
    import org.apache.flink.util.NumberSequenceIterator
    
    /**
      * @Author Daniel
      * @Description Flink Source——基于集合
      *
      **/
    object FromCollection {
      def main(args: Array[String]): Unit = {
        val dSEnvironment = ExecutionEnvironment.getExecutionEnvironment
        val dataset1: DataSet[Int] = dSEnvironment.fromElements(1, 2, 3, 4, 5)
        val dataset2: DataSet[String] = dSEnvironment.fromCollection(Iterator("Baidu", "Google", "Bing", "Yahoo"))
        val dataset3: DataSet[String] = dSEnvironment.fromCollection(Array[String]("Flink", "Spark", "Hadoop"))
        val dataset4: DataSet[lang.Long] = dSEnvironment.fromParallelCollection(new NumberSequenceIterator(1, 10))
        val dataset5: DataSet[Long] = dSEnvironment.generateSequence(10, 20)
        println("---------------------从Java.util.Collection创建数据流-----------------------")
        dataset1.print()
        println("---------------------从一个迭代器中创建数据流-----------------------")
        dataset2.print()
        println("---------------------从给定的对象序列中创建数据流-----------------------")
        dataset3.print()
        println("---------------------从一个迭代器中创建并行数据流-----------------------")
        dataset4.print()
        println("---------------------创建一个生成指定区间范围内的数字序列的并行数据流-----------------------")
        dataset5.print()
      }
    
    }
    

2.基于文件

  1. readTextFile(path) 读取文本文件,即符合 TextInputFormat 规范的文件,并将其作为字符串返回

  2. readTextFileWithValue(path)/ TextValueInputFormat 按行读取文件并将它们作为 StringValues 返回。StringValues 是可变字符串

  3. readCsvFile(path)/ CsvInputFormat 解析逗号(或其他字符)分隔的文件。返回元组,case class 对象或 POJO 的 DataSet。支持基本 java 类型及其 value 对应作为字段类型

  4. readFileOfPrimitives(path,delimiter)/ PrimitiveInputFormat 使用给定的分隔符来解析 new-line (或则 另外 char sequence) 文件。被分割的原始数据类 型,如 String 或 Integer。此方法类似于具有单个字段的 readCsvFile(String),但它不通过 Tuple1 生成 DataSet。

  5. readFile(fileInputFormat, path) 根据指定的文件输入格式读取文件(一次)

  6. createInput(inputFormat)/ InputFormat 接受通用输入格式读取数据

    FromFile.scala

    package blog.source
    
    import org.apache.flink.api.java.io.TextInputFormat
    import org.apache.flink.api.scala.{DataSet, ExecutionEnvironment, _}
    import org.apache.flink.types.StringValue
    import template.sink.Batch.Student
    import org.apache.flink.core.fs.Path
    
    /**
      * @Author Daniel
      * @Description Flink Source——基于文件
      *
      **/
    object FromFile {
      def main(args: Array[String]): Unit = {
        val localFilePath: String = "file:///F:/IdeaProjects/flink_project/student.txt"
        val dSEnvironment = ExecutionEnvironment.getExecutionEnvironment
        val dS1: DataSet[String] = dSEnvironment.readTextFile(localFilePath)
        val dS2: DataSet[StringValue] = dSEnvironment.readTextFileWithValue(localFilePath, "UTF-8")
        val dS3: DataSet[Student] = dSEnvironment.readCsvFile[Student](
          //文件路径
          filePath = "file:///F:/IdeaProjects/flink_project/student.txt",
          //行分隔符
          lineDelimiter = "\n",
          //列分隔符
          fieldDelimiter = ",",
          //不解析掉包裹在该字符中的一切字符,默认为null
          quoteCharacter = '"',
          //去掉第一行(表头),默认为false
          ignoreFirstLine = true,
          //忽略掉"#"开头的注释,默认为null
          ignoreComments = "#",
          //启用松散解析,是否忽略错误的格式,默认为false
          lenient = true,
          //选择需要的字段,默认所有字段
          includedFields = Array[Int](0, 1, 2, 3),
          //将CSV文件的字段映射为POJO字段,一定要和泛型类的结构对应
          pojoFields = Array[String]("id", "name", "sex", "age")
        )
        val dS4: DataSet[String] = dSEnvironment.readFileOfPrimitives[String](localFilePath, delimiter = "\n")
        val dS5: DataSet[String] = dSEnvironment.readFile(new TextInputFormat(new Path(localFilePath)), localFilePath)
        val dS6: DataSet[String] = dSEnvironment.createInput(new TextInputFormat(new Path(localFilePath)))
        println("---------------------读取文本文件-----------------------")
        dS1.print()
        println("---------------------按行读取文件并将它们作为StringValues返回-----------------------")
        dS2.print()
        println("---------------------解析逗号(或其他字符)分隔的文件-----------------------")
        dS3.print()
        println("---------------------使用给定的分隔符来解析文件-----------------------")
        dS4.print()
        println("---------------------根据指定的文件输入格式读取文件(一次)-----------------------")
        dS5.print()
        println("---------------------接受通用输入格式读取数据-----------------------")
        dS6.print()
    
      }
    
    }
    

补充两点:

1.递归遍历输入路径目录

对于基于文件的输入,当输入路径是目录时,默认情况下不会枚举嵌套文件。 相反,只读取基目录中的文件,而忽略嵌套文件。可以通过 recursive.file.enumeration 配置参数启用嵌 套文件的递归遍历,如下例所示:

// enable recursive enumeration of nested input files
val env = ExecutionEnvironment.getExecutionEnvironment
// create a configuration object
val parameters = new Configuration
// set the recursive enumeration parameter
parameters.setBoolean("recursive.file.enumeration", true)
// pass the configuration to the data source
env.readTextFile("file:///path/with.nested/files").withParameters(parameters)

2.基于压缩文件

Flink 目前支持输入文件的透明解压缩,如果它们标有适当的文件扩展名,不过并不建议使用。这意味着不需要进一步配置输入格式,并且任何 FileInputFormat 都支持压缩,包括自定义输入格式。 请注意,压缩文件可能无法并行读取,从而影响作业可伸缩性。 下表列出了当前支出的压缩方法:

压缩方法 File 格式
DEFLATE .deflate
GZip .gz, .gzip
Bzip2 .bz2
Xz .xz

3.基于 Socket

  • socketTextStream(String hostname, int port) 从 socket 读取。元素可以用分隔符切分

    FromSocket.scala

    package blog.source
    
    import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
    
    /**
      * @Author Daniel
      * @Description Flink Source——基于Socket
      *
      **/
    object FromSocket {
      def main(args: Array[String]): Unit = {
        val streamEnv = StreamExecutionEnvironment.getExecutionEnvironment
        val dS = streamEnv.socketTextStream("hadoop01", 9999)
        println("---------------------从网络端口读取流数据-----------------------")
        dS.print()
      }
    }
    

4.自定义

自定义的 source 常见的有 Apache Kafka、Amazon Kinesis Streams、RabbitMQ、Apache NiFi、 Twitter Streaming API 等,当然也可以定义自己的 source
Flink编程三大组件(一)——Source_第1张图片

  • addSource(new SourceFunction()) 添加一个新的 source function。例如:addSource(new FlinkKafkaConsumer011<>(„)) 以从 Apache Kafka 读取数据

    MySQLSource.scala

    package blog.source
    
    import java.sql.{Connection, DriverManager, PreparedStatement}
    
    import org.apache.flink.configuration.Configuration
    import org.apache.flink.streaming.api.functions.source.{RichSourceFunction, SourceFunction}
    import template.sink.Batch.Student
    
    /**
      * @Author Daniel
      * @Description Flink Source——自定义
      *
      **/
    class MySQLSource extends RichSourceFunction[Student] {
    
      var ps: PreparedStatement = _
      var conn: Connection = _
    
      // open()方法中建立连接,这样不用每次invoke的时候都要建立连接和释放连接。
      override def open(parameters: Configuration): Unit = {
        val driver = "com.mysql.jdbc.Driver"
        val url = "jdbc:mysql://localhost:3306/flink"
        val username = "root"
        val password = "root"
        //1.加载驱动
        Class.forName(driver)
        //2.创建连接
        conn = DriverManager.getConnection(url, username, password)
        //3.获得执行语句
        val sql = "select id,name,sex,age, department from student;"
        ps = conn.prepareStatement(sql)
      }
    
      override def cancel(): Unit = {
        println("cancel...")
      }
    
      //DataStream调用run()方法用来获取数据
      override def run(sourceContext: SourceFunction.SourceContext[Student]): Unit = {
        try { //4.执行查询,封装数据
          val resultSet = ps.executeQuery
          while (resultSet.next) {
            val student = Student(
              resultSet.getString("id"),
              resultSet.getString("name").trim,
              resultSet.getString("sex").trim,
              resultSet.getString("age"))
            sourceContext.collect(student)
          }
        } catch {
          case e: Exception =>
            e.printStackTrace()
        }
      }
    
      //程序执行完毕后关闭连接和释放资源
      override def close(): Unit = { //5.关闭连接和释放资源
        super.close
        if (conn != null) conn.close
        if (ps != null) ps.close
      }
    }
    

    dept.sql

    -- ----------------------------
    -- Table structure for student
    -- ----------------------------
    DROP TABLE IF EXISTS `student`;
    CREATE TABLE `student`  (
      `id` int(11) NOT NULL,
      `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `sex` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      `age` int(30) NULL DEFAULT NULL,
      `department` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of student
    -- ----------------------------
    INSERT INTO `student` VALUES (95002, '刘晨', '女', 19, 'IS');
    INSERT INTO `student` VALUES (95013, '欧阳少恭', '男', 21, 'CS');
    INSERT INTO `student` VALUES (95017, '王风娟', '女', 18, 'IS');
    INSERT INTO `student` VALUES (95018, '王一', '女', 19, 'IS');
    

    MySource.scala

    package blog.source
    
    import org.apache.flink.streaming.api.scala.{StreamExecutionEnvironment, _}
    
    /**
    * @Author Daniel
    * @Description Flink Source——自定义
    *
    **/
    object MySource {
    def main(args: Array[String]): Unit = {
    
    //1.创建流执行环境
    val env = StreamExecutionEnvironment.getExecutionEnvironment
    
    //2.从自定义source中读取数据
    val students = env.addSource(new MySQLSource)
    
    //3.显示结果
    students.print().setParallelism(1)
    
    //4.触发流执行
    env.execute("Flink Custom Source")
    
    	}
    }
    

总结:

  1. 基于集合:有界数据集,更偏向于本地测试用
  2. 基于文件:适合监听文件修改并读取其内容
  3. 基于 Socket:监听主机的 host:port,从 Socket 中获取数据
  4. 自定义 addSource:大多数的场景数据都是无界的,会源源不断的过来。比如去消费 Kafka 某个 topic 上的数据,这时候就需要用到这个 addSource,可能因为用的比较多的原 因吧,Flink 直接提供了 FlinkKafkaConsumer011 等类直接使用。FlinkKafkaConsumerBase 类,它是 Flink Kafka 消费的最根本的类

你可能感兴趣的:(Flink,flink)