Flink API - 富函数
我们经常会有这样的需求:在函数处理数据之前,需要做一些初始化的工作;或者需要在处理数据时可以获得函数执行上下文的一些信息;以及在处理完数据时做一些清理工作。而 DataStream API 就提供了这样的机制。
DataStream API 提供的所有转换操作函数,都拥有它们的“富”版本,并且我们在使用常规函数或者匿名函数的地方来使用富函数。例如下面就是富函数的一些例子,可以看出,只需要在常规函数的前面加上Rich 前缀就是富函数了。
● RichMapFunction
● RichFlatMapFunction
● RichFilterFunction
● …
当我们使用富函数时,我们可以实现两个额外的方法:
● open() 方法是 rich function 的初始化方法,当一个算子例如 map 或者 filter 被调用之前 open() 会被调用。open() 函数通常用来做一些只需要做一次即可的初始化工作。
● close() 方法是生命周期中的最后一个调用的方法,通常用来做一些清理工作。
另外,getRuntimeContext()方法提供了函数的RuntimeContext的一些信息,例如函数执行的并行度,当前子任务的索引,当前子任务的名字。同时还它还包含了访问分区状态的方法。
public class RichFunctionRichMap {
/*
常规函数的前面加上Rich前缀就是富函数
● RichMapFunction
● RichFlatMapFunction
● RichFilterFunction
● …
用富函数时,可以实现两个额外的方法:
● open()方法是rich function的初始化方法,当一个算子例如map或者filter被调用之前open()会被调用。open()函数通常用来做一些只需要做一次即可的初始化工作。
● close()方法是生命周期中的最后一个调用的方法,通常用来做一些清理工作。
另外,getRuntimeContext()方法提供了函数的RuntimeContext的一些信息,例如函数执行的并行度,当前子任务的索引,当前子任务的名字。同时还它还包含了访问分区状态的方法
*/
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
env
.fromElements(1, 2, 3, 4)
.map(new RichMapFunction<Integer, Integer>() {
// 针对每一个任务槽开启生命周期
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
RuntimeContext context = getRuntimeContext();
System.out.println("生命周期开始,当前子任务的索引是:" + context.getIndexOfThisSubtask());
}
@Override
public Integer map(Integer value) throws Exception {
return value * value;
}
@Override
public void close() throws Exception {
super.close();
System.out.println("生命周期结束");
}
})
.print();
env.execute();
}
}
Flink API - Source
在这先简单介绍 Flink 与外部系统的数源连接,详细内容将在后续的 Flink 读写外部系统中进行详细介绍
从集合读取数据
// source from collect
public static void main(String[] args) throws Exception{
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
env
.fromCollection(
Arrays.asList("tom","jock","alick")
);
env.fromElements("tom","jock","alick");
env.execute();
}
从文件读取
env.readTextFile("1.txt")
从 socket 读取
env.socketTextStream("127.0.0.1", 9999);
从 kafka 读取
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka</artifactId>
<version>${flink.version}</version>
</dependency>
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
// old
Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "hadoop102:9092,hadoop103:9092,hadoop104:9092");
properties.setProperty("group.id", "test-group-id");
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");
// FlinkKafkaConsumer<String> kafkaConsumer = new FlinkKafkaConsumer<>("test-topic", new SimpleStringSchema(), properties);
// env.addSource(kafkaConsumer).print();
// new
// KafkaSource<String> source = KafkaSource
// .<String>builder()
// .setBootstrapServers(KafkaSourceTestEnv.brokerConnectionStrings)
// .setGroupId("MyGroup")
// .setTopics(Arrays.asList(TOPIC1, TOPIC2))
// .setDeserializer(new TestingKafkaRecordDeserializationSchema())
// .setStartingOffsets(OffsetsInitializer.earliest())
// .build();
KafkaSource<String> kafkaSource = KafkaSource
.<String>builder()
.setBootstrapServers("hadoop102:9092,hadoop103:9092,hadoop104:9092")
.setTopics(Arrays.asList("test-topic"))
.setGroupId("test-group-id")
.setStartingOffsets(OffsetsInitializer.latest())
.setValueOnlyDeserializer(new SimpleStringSchema())
.build();
DataStreamSource<String> streamSource = env
.fromSource(kafkaSource, WatermarkStrategy.noWatermarks(), "kafka-source");
streamSource.print();
env.execute();
}
consumer source
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
// consumer source
DataStreamSource<Event> streamSource = env.addSource(new ClickSource());
streamSource
// 实现 print
.addSink(new SinkFunction<Event>() {
@Override
public void invoke(Event value, SinkFunction.Context context) throws Exception {
SinkFunction.super.invoke(value, context);
System.out.println(value);
}
});
env.execute();
}
// SourceFunction并行度只能为1
// 自定义并行化版本的数据源,需要使用ParallelSourceFunction
public static class ClickSource implements SourceFunction<Event> {
private boolean running = true;
private String[] userArr = {"Mary", "Bob", "Alice", "Liz"};
private String[] urlArr = {"./home", "./cart", "./fav", "./prod?id=1", "./prod?id=2"};
private Random random = new Random();
@Override
public void run(SourceContext<Event> ctx) throws Exception {
while (running) {
// collect方法,向下游发送数据
ctx.collect(
new Event(
userArr[random.nextInt(userArr.length)],
urlArr[random.nextInt(urlArr.length)],
Calendar.getInstance().getTimeInMillis()
)
);
Thread.sleep(1000L);
}
}
@Override
public void cancel() {
running = false;
}
}
public static class Event {
public String user;
public String url;
public Long timestamp;
public Event() {
}
public Event(String user, String url, Long timestamp) {
this.user = user;
this.url = url;
this.timestamp = timestamp;
}
@Override
public String toString() {
return "Event{" +
"user='" + user + '\'' +
", url='" + url + '\'' +
", timestamp=" + new Timestamp(timestamp) +
'}';
}
}