【Flink】Source 源算子 『fromCollection() | readTextFile() | socketTextStream | addSource() | Flink流支持的数据』

  • Flink 直接连接的数据源:语法为执行环境.对应的方法()。比如env.readTextFile()
  • Flink使用连接器连接的数据源:语法为执行环境.addSource(连接器对象)。比如env.addSource(new FlinkKafkaConsumer<>())

注意:无论是哪种方式获取数据源,反序列的元素有要求:为Flink流支持的数据类型【相关知识点在第3节】

1. Flink 直接连接的数据源

1.1 从 集合 中读取数据(用于有界流数据的测试场景)

  1. env.fromCollection(集合对象)读取数据。例如:
    public static void main(String[] args) throws Exception {
    	// 获取执行环境
    	StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    	// 设置全局并行度
    	env.setParallelism(1);
    	// 构造源数据
    	ArrayList<Event> clicks = new ArrayList<>();
    	clicks.add(new Event("Mary","./home",1000L));
    	clicks.add(new Event("Bob","./cart",2000L));
    	// 读取源数据
    	DataStream<Event> stream = env.fromCollection(clicks);
    	// 打印源数据
    	stream.print();
    	// 触发执行程序
    	env.execute();
    }
    
  2. env.fromElements(元素1, 元素2, ...)读取数据。例如:
    // 元素可以是对象
    DataStreamSource<Event> stream2 = env.fromElements(
    	new Event("Mary", "./home", 1000L),
    	new Event("Bob", "./cart", 2000L),
    );
    
    // 元素也可以是基本数据类型,还可以是其它数据类型,具体见下面的第3节--flink流支持的数据类型
    DataStreamSource<Integer> stream2 = env.fromElements(123);
    

1.2. 从 文件 读取数据(用于有界流数据的实际场景)

  • env.readTextFile()读取数据。例如:

    DataStream<String> stream = env.readTextFile("clicks.csv");
    

    注意:

    1. 参数可以是目录,也可以是文件;
    2. 参数也可以是HDFS路径(hdfs://192.168.10.111:8020/flink/words.txt)。Flink作为客户端连入Hadoop集群,因此需要pom.xml 中添加相关依赖
      <dependency>
      	<groupId>org.apache.hadoop</groupId>
      	<artifactId>hadoop-client</artifactId>
      	<!-- 注意版本于Hadoop集群的版本一致 -->
      	<version>3.3.1</version>
      	<scope>provided</scope>
      </dependency>
      
    3. 路径可以是相对路径,也可以是绝对路径;
      ① idea中相对路径是 project 的根目录
      ② standalone 模式下相对路径是集群节点根目录;

1.3 从 Socket 读取数据(用于无界流数据的测试场景)

  • env.socketTextStream()读取数据。例如:

    DataStream<String> stream = env.socketTextStream("localhost", 7777);
    

2. Flink使用连接器连接的数据源

4.1 从 Kafka 读取数据(用于无界流数据的实际场景)

  1. 首先在 pom.xml 文件中导入 kafka 依赖:

    <dependency>
    	<groupId>org.apache.flink</groupId>
    	<artifactId>flink-connector-kafka_${scala.binary.version}</artifactId>
    	<version>${flink.version}</version>
    </dependency>
    
  2. 再使用env.addSource(new FlinkKafkaConsumer<>())读取kafka数据。例如:

    Properties properties = new Properties();
    properties.setProperty("bootstrap.servers", "hadoop102:9092");
    properties.setProperty("group.id", "consumer-group");
    
    DataStreamSource<String> stream = env.addSource(new FlinkKafkaConsumer<String>(
    	"clicks",
    	new SimpleStringSchema(),
    	properties
    ));
    

    注意:创建 FlinkKafkaConsumer 时需要传入3个参数

    1. 第一个参数定义了从哪些主题中读取数据。可以是一个 topic,也可以是 topic列表,还可以是匹配所有想要读取的 topic 的正则表达式。当从多个 topic 中读取数据时,Kafka 连接器将会处理所有 topic 的分区,将这些分区的数据放到一条流中去。
    2. 第二个参数定义了将kafka字节数据反序列化为什么数据。需传入DeserializationSchema KeyedDeserializationSchema接口的实现类的对象。
    3. 第三个参数是一个 Properties 对象,设置了 Kafka 客户端的一些属性。

4.2 自定义连接器

  1. 定义一个类继承 SourceFunctionParallelSourceFunction接口。

    注意:前者用于非并行读取;后者用于并行读取。也就是说实现SourceFunction 接口的连接器,并行度只能设置为1,比如

    // ClickSource是继承SourceFunction接口的连接器
    env.addSource(new ClickSource()).setParallelism(2).print(); // 会抛异常,因为它的并行	度只能为1
    
  2. 重写两个关键方法:
    1. run()方法:使用运行时上下文对象(SourceContext)向下游发送数据;
    2. cancel()方法:通过标识位控制退出循环,来达到中断数据源的效果。
      package com.hao.wordcount;
      
      import org.apache.flink.streaming.api.functions.source.SourceFunction;
      import java.util.Calendar;
      import java.util.Random;
      public class ClickSource implements SourceFunction<Event> {
          // 声明一个布尔变量,作为控制数据生成的标识位
          private Boolean running = true;
      
          @Override
          public void run(SourceContext<Event> ctx) throws Exception {
              Random random = new Random(); // 在指定的数据集中随机选取数据
              String[] users = {"Mary", "Alice", "Bob", "Cary"};
              String[] urls = {"./home", "./cart", "./fav", "./prod?id=1", "./prod?id=2"};
              while (running) {
                  ctx.collect(new Event(
                          users[random.nextInt(users.length)],
                          urls[random.nextInt(urls.length)],
                          Calendar.getInstance().getTimeInMillis()
                  ));
                  // 隔 1 秒生成一个点击事件,方便观测
                  Thread.sleep(1000);
              }
          }
      
          @Override
          public void cancel() {
              running = false;
          }
      }
      
  3. 使用连接器连接读取数据
    import org.apache.flink.streaming.api.datastream.DataStreamSource;
    import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
    public class SourceCustom {
        public static void main(String[] args) throws Exception {
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
            env.setParallelism(1);
    		//有了自定义的 source function,调用 addSource 方法
            DataStreamSource<Event> stream = env.addSource(new ClickSource());
            stream.print("SourceCustom");
            env.execute();
        }
    }
    

3. Flink流支持的数据类型

  • 将读取的数据流反序列化为java对象时,对该java对象类有4个要求:
    1. 类是公共的(public)和独立的(standalone,也就是说没有非静态的内部类);
    2. 类有一个公共的无参构造方法;
    3. 类中的所有字段是 public 且非 final 的;或者有一个公共的 getter 和 setter 方法,这些
      方法需要符合 Java bean 的命名规范。
  • 内置的满足要求的数据类型:
    1. 基本类型:所有 Java 基本类型及其包装类,再加上 VoidStringDateBigDecimalBigInteger
    2. 数组类型:包括基本类型数组和对象数组
    3. 复合数据类型:
      1. Java 元组类型。最多25 个字段,也就是从 Tuple0~Tuple25,不支持空字段
      2. 行类型(ROW):可以认为是具有任意个字段的元组,并支持空字段
    4. 辅助类型:Option、Either、List、Map 等
    5. 泛型类型(GENERIC)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ElegantCodingWH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值