文章目录
- Flink 直接连接的数据源:语法为
执行环境.对应的方法()
。比如env.readTextFile()
- Flink使用连接器连接的数据源:语法为
执行环境.addSource(连接器对象)
。比如env.addSource(new FlinkKafkaConsumer<>())
注意:无论是哪种方式获取数据源,反序列的元素有要求:为Flink流支持的数据类型【相关知识点在第3节】
1. Flink 直接连接的数据源
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(); }
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(1, 2, 3);
1.2. 从 文件 读取数据(用于有界流数据的实际场景)
-
env.readTextFile()
读取数据。例如:DataStream<String> stream = env.readTextFile("clicks.csv");
注意:
- 参数可以是目录,也可以是文件;
- 参数也可以是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>
- 路径可以是相对路径,也可以是绝对路径;
① idea中相对路径是 project 的根目录
② standalone 模式下相对路径是集群节点根目录;
1.3 从 Socket 读取数据(用于无界流数据的测试场景)
-
env.socketTextStream()
读取数据。例如:DataStream<String> stream = env.socketTextStream("localhost", 7777);
2. Flink使用连接器连接的数据源
4.1 从 Kafka 读取数据(用于无界流数据的实际场景)
-
首先在 pom.xml 文件中导入 kafka 依赖:
<dependency> <groupId>org.apache.flink</groupId> <artifactId>flink-connector-kafka_${scala.binary.version}</artifactId> <version>${flink.version}</version> </dependency>
-
再使用
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个参数
- 第一个参数定义了从哪些主题中读取数据。可以是一个 topic,也可以是 topic列表,还可以是匹配所有想要读取的 topic 的正则表达式。当从多个 topic 中读取数据时,Kafka 连接器将会处理所有 topic 的分区,将这些分区的数据放到一条流中去。
- 第二个参数定义了将kafka字节数据反序列化为什么数据。需传入
DeserializationSchema
或KeyedDeserializationSchema
接口的实现类的对象。 - 第三个参数是一个 Properties 对象,设置了 Kafka 客户端的一些属性。
4.2 自定义连接器
- 定义一个类继承
SourceFunction
或ParallelSourceFunction
接口。注意:前者用于非并行读取;后者用于并行读取。也就是说实现SourceFunction 接口的连接器,并行度只能设置为1,比如
// ClickSource是继承SourceFunction接口的连接器 env.addSource(new ClickSource()).setParallelism(2).print(); // 会抛异常,因为它的并行 度只能为1
- 重写两个关键方法:
- run()方法:使用运行时上下文对象(SourceContext)向下游发送数据;
- 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; } }
- 使用连接器连接读取数据
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个要求:
- 类是公共的(public)和独立的(standalone,也就是说没有非静态的内部类);
- 类有一个公共的无参构造方法;
- 类中的所有字段是 public 且非 final 的;或者有一个公共的 getter 和 setter 方法,这些
方法需要符合 Java bean 的命名规范。
- 内置的满足要求的数据类型:
- 基本类型:所有 Java 基本类型及其包装类,再加上
Void
、String
、Date
、BigDecimal
和BigInteger
。 - 数组类型:包括基本类型数组和对象数组
- 复合数据类型:
- Java 元组类型。最多25 个字段,也就是从 Tuple0~Tuple25,不支持空字段
- 行类型(ROW):可以认为是具有任意个字段的元组,并支持空字段
- 辅助类型:Option、Either、List、Map 等
- 泛型类型(GENERIC)
- 基本类型:所有 Java 基本类型及其包装类,再加上