Flink 流处理API
1 Environment执行环境
1.1 getExecutionEnvironment
创建一个执行环境,表示当前执行程序的上下文。 如果程序是独立调用的,则此方法返回本地执行环境;如果从命令行客户端调用程序以提交到集群,则此方法返回此集群的执行环境,也就是说,getExecutionEnvironment
会根据查询运行的方式决定返回什么样的运行环境,是最常用的一种创建执行环境的方式。
1.2 createLocalEnvironment
可以直接在本地创建一个执行环境,有一个参数是用来设置执行环境的并行度;
1.3 createLocalEnvironmentWithWebUI(new Configuration())
在本地的web端直接创建一个执行环境,这样的好处是在env运行的时候可以直接在网络端口查看代码的运行情况,网络地址为localhost:8081
;
1.3createRemoteEnvironment
返回集群执行环境,将Jar提交到远程服务器。需要在调用时指定JobManager的IP和端口号,并指定要在集群中运行的Jar包。
// 代码样例EnironmentDemo
package StudyFlink.DataStream.API.Environmen;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.environment.LocalStreamEnvironment;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
public class getExecutionEnvironment {
public static void main(String[] args) {
// 创建执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 设置并行度
env.setParallelism(1);
// 返回本地的执行环境,需要在调用时指定默认的并行度
LocalStreamEnvironment localEnv = StreamExecutionEnvironment.createLocalEnvironment();
// 创建一个本地的web执行环境,localhost:8081;可以在线查看jar包的执行情况;
StreamExecutionEnvironment localEnvWithWebUI = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
// 返回集群的执行环境,将Jar包提交到远程服务器。需要在调用时指定JobManager的Ip和端口号,并指定要在集群中运行的Jar包
StreamExecutionEnvironment removteEnv = StreamExecutionEnvironment.createRemoteEnvironment("jobmanager-hostname", 6123, "YOURPATH//wordcount.jar");
}
}
2 Source读取数据源
定义一个POJO类;
package StudyFlink.DataStream.API.Beans;
/*
传感器温度读数的数据类型;
*/
public class SensorReading {
// 属性
private String id;
private Long timeStamp;
private Double temperature;
// 无参构造方法
public SensorReading() {
}
// 有参构造方法
public SensorReading(String id, Long timeStamp, Double temperature) {
this.id = id;
this.timeStamp = timeStamp;
this.temperature = temperature;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Long timeStamp) {
this.timeStamp = timeStamp;
}
public Double getTemperature() {
return temperature;
}
public void setTemperature(Double temperature) {
this.temperature = temperature;
}
@Override
public String toString() {
return "SensorReading{" +
"id='" + id + '\'' +
", timeStamp=" + timeStamp +
", temperature=" + temperature +
'}';
}
}
2.1 从集合中读取数据
package StudyFlink.DataStream.API.Source;
import StudyFlink.DataStream.API.Beans.SensorReading;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import java.util.Arrays;
public class collection {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 从集合中读取数据
DataStreamSource<SensorReading> dataSource = env.fromCollection(Arrays.asList(
new SensorReading("01", 10000L, 36.2),
new SensorReading("02", 10001L, 36.3)
));
// 直接从元素中获取
DataStreamSource<Integer> elementSource = env.fromElements(1, 2, 3, 4, 5);
// 输出的print可以传递参数;
dataSource.print("SensorReading输出");
elementSource.print("整数输出");
// 执行任务,jobName
env.execute("SourceJob");
}
}
2.2 从文件中读取数据
// sensor.txt
"01",10000,33.6
"02",10001,33.4
"03",10002,33.9
"01",10003,33.0
"02",10004,33.8
package StudyFlink.DataStream.API.Source;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
public class fromFile {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 从文件中读取,但是这个读取之后的结果是一个字符串,需要在后续的操作中进行map操作
DataStreamSource<String> dataSource = env.readTextFile("resources\\sensor.txt");
dataSource.print();
env.execute();
}
}
2.3 从Kafka消息队列中读取数据
首先需要去启动zookeeper,然后启动kafka;
package StudyFlink.DataStream.API.Source;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
import java.util.Properties;
public class kafka {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 设置与kafka之间的连接
Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "localhost:9092");
properties.setProperty("group.id", "consumer-group");
properties.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
properties.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
properties.setProperty("auto.offset.reset", "latest");
// 从kafka中获取消息队列
// 因为kafka是一个外部组件,获取消息必须通过addSource连接器连接;
// FlinkKafkaConsumer消费者,需要传递的参数:主题String、反序列化的方法、和Properties
DataStreamSource<String> dataSource = env.addSource(new FlinkKafkaConsumer011<String>("sensor", new SimpleStringSchema(), properties));
dataSource.print();
env.execute();
}
}
2.4 自定义Source
除了以上的source数据来源,我们还可以自定义source。需要做的,只是传入一个SourceFunction就可以。
// 希望可以随机生成传感器的温度数据
package StudyFlink.DataStream.API.Source;
import StudyFlink.DataStream.API.Beans.SensorReading;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import org.apache.flink.table.expressions.Rand;
import java.util.HashMap;
import java.util.Random;
public class mySensor {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
DataStreamSource<SensorReading> dataStream = env.addSource(new MySensorSource());
dataStream.print();
env.execute();
}
// 实现自定义的SourceFunction,他需要实现SourceFunction函数
private static class MySensorSource implements SourceFunction<SensorReading> {
// 定义一个标识位,用来控制数据的产生
private boolean running = true;
@Override
public void run(SourceContext<SensorReading> ctx) throws Exception {
// 定义一个随机数生成器
Random random = new Random();
// 设置10个传感器的初始温度;
HashMap<String, Double> sensorTempMap = new HashMap<>();
for (int i = 0; i < 10; i++) {
// 收集传感器的名称和一个高斯分布的随机初始温度值
sensorTempMap.put("sensor_"+(i+1),60+random.nextGaussian()*20);
}
// 参数ctx是一个收集器;
while (running){
for (String sensorId : sensorTempMap.keySet()) {
// 在当前温度的基础上随机波动
double newTemp = sensorTempMap.get(sensorId) + random.nextGaussian();
sensorTempMap.put(sensorId,newTemp);
// 收集新的数据
ctx.collect(new SensorReading(sensorId,System.currentTimeMillis(),newTemp));
}
// 控制输出频率
Thread.sleep(1000L);
}
}
@Override
public void cancel() {
running = false;
}
}
}
3 Transform 转换算子
基本转换算子的定义:作用在数据流中的每一条单独的数据上的算子。
基本转换算子会针对流中的每一个单独的事件做处理,也就是说每一个输入数据会产生一个输出数据。
单值转换,数据的分割,数据的过滤,都是基本转换操作的典型例子。
3.1 map
来一个处理一个,中间只是做一些简单的处理;一对一进行处理;可以转换数据类型;
例如,将获取的温度传感器的字符串数据转换成sensorReading的格式;
3.2flatMap
和Map最大的不同之处就是flatMap是一对多的输出,而Map函数是一对一的输出;
flatmap是将数据打散,进行一些拆分操作;例如对输入的String字符串按照某种个数做拆分然后再进行输出;
输入为一个,输出为多个,中间使用收集器Collector进行收集数据;
例如,在wordCount案例当中,每次从socket中获取的字符串有可能是多个,需要按照逗号将其分开,然后利用Collector收集器收集分隔之后的单词,这样的过程就是一个输入是一个字符串,输出却是多个字符串的过程;
3.3 Filter
对数据按照一定的规则做一些筛选和过滤;例如,传感器的温度当中筛选出高于一定温度的数据,对这部分数据进行输出;
filter不能改变数据类型;
//E:\Flink\DataFromMyself_ExcelData\src\main\java\StudyFlink\DataStream\API\transform\base_transform.java
package StudyFlink.DataStream.API.transform;
import StudyFlink.DataStream.API.Beans.SensorReading;
import org.apache.flink.api.common.functions.FilterFunction;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.Utils;
import org.apache.flink.api.java.typeutils.TypeExtractor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
import org.apache.flink.util.Collector;
import java.util.HashMap;
import java.util.Random;
/*
一些基本的转换算子操作;
*/
public class base_transform {
public static void main(String[] args) throws Exception {
// 创建执行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironmentWithWebUI(new Configuration());
env.setParallelism(1);
// 自定义数据源
DataStreamSource<String> dataStream = env.readTextFile("E:\\Flink\\DataFromMyself_ExcelData\\src\\main\\resources\\sensor.txt");
// 基本转换:map
// 将读取的字符串,转换成该字符串的长度并进行输出
DataStream<Integer> mapStream = dataStream.map(new MapFunction<String, Integer>() {
@Override
public Integer map(String value) throws Exception {
// value是输入数据