1、一个flink任务的不同状态
我们先来简单看下,一个flink任务从创建到消亡会经历哪些状态。在启动一个Flink job的时候,可以从控制台看到job和task的多个状态的切换
Flink job的状态变化
在执行ExecutionMap期间,每个并行任务经历多个阶段,从创建到完成或失败。
2、一个简单的flink任务
//1. 构建执行环境
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//2. 定义数据源(source),这里使用监听9000端口的socket消息,通常也可用来测试flink任务
DataStream<String> socketTextStream = env.socketTextStream("localhost", 9000, "\n");
//3. 打印dataStream内容
socketTextStream.print();
//4. 执行
env.execute();
source:
在命令行(以mac为例),输入:nc -lk 9000
qwer
qwer123
**flink:**在idea的控制台可看到从socekt接收到的message
1> qwer
2> qwer123
3、常见算子
3.1 Map
DataStream → DataStream,流属性不变
就像传统的map数据结构,一个key对应一个value,map算子一个输入对应一个输出
private static final Joiner ADD_JOINER = Joiner.on(":");
private static void testSocket() throws Exception{
//1. 构建执行环境
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
//2. 定义数据源(source),这里使用监听9000端口的socket消息,通常也可用来测试flink任务
DataStream<String> socketTextStream = env.socketTextStream("localhost", 9000, "\n");
//3. map
DataStream<String> mapSocketTextStream = socketTextStream.map(new MapFunction<String, String>() {
@Override
public String map(String value) throws Exception {
return ADD_JOINER.join("socket message", value);
}
});
//lambda表达
DataStream<String> mapSocketTextStream = socketTextStream
.map((MapFunction<String, String>) value -> ADD_JOINER.join("socket message", value));
//4. 打印dataStream内容
mapSocketTextStream.print();
//5. 执行
env.execute();
}
source:
mingzhoudeMacBook-Pro:~ ming.zhou$ nc -lk 9000
test flink
flink:
1> socket message:test flink
3.2 flatMap
DataStream → DataStream,流属性不变
相当于平铺,输入一个元素,输出0、一个或多个元素,以下是是以空格分割字符串,并输出分割后的字符串集合
DataStream<String> flatMapSocketTextStream = socketTextStream.flatMap(new FlatMapFunction<String, String>() {
@Override
public void flatMap(String value, Collector<String> out) throws Exception {
for (String v : value.split(" ")) {
out.collect(v);
}
}
});
source:
mingzhoudeMacBook-Pro:~ ming.zhou$ nc -lk 9000
hello flink
flink:
1> hello
1> flink
值得注意的是,flatMap算子使用lambda表达式的时候会有如下异常:
Exception in thread “main” org.apache.flink.api.common.functions.InvalidTypesException: The return type of function ‘testSocket(SocketFlinkMain.java:31)’ could not be determined automatically, due to type erasure. You can give type information hints by using the returns(…) method on the result of the transformation call, or by letting your function implement the ‘ResultTypeQueryable’ interface.
Caused by: org.apache.flink.api.common.functions.InvalidTypesException: The generic type parameters of ‘Collector’ are missing.
这是因为Flink在用户自定义的函数中会使用泛型来创建serializer,当我们使用匿名函数时,类型信息会被保留。但Lambda表达式并不是匿名函数,所以javac编译的时候并不会把泛型保存到class文件里。
可以使用Flink提供的returns方法来指定flatMap的返回类型
http://kane-xie.github.io/2017/07/12/2017-07-12_Flink使用lambda表达式/
3.3 filter
DataStream → DataStream,流属性不变
过滤器,对数据流中的每个元素进行过滤判断,判断为true的元素进入下一个数据流
DataStream<String> filterSocketTextStream = socketTextStream
.filter((FilterFunction<String>) value -> value.startsWith("socket"));
source:
mingzhoudeMacBook-Pro:~ ming.zhou$ nc -lk 9000
test flink
socket flink
flink:
2> socket flink
3.4 keyBy
DataStream → KeyedStream
将数据流按照key分成多个不相交的分区,相同的key的记录会被分到同一个分区中,keyBy()是通过散列分区实现的。
我们可以将一个pojo类的一个或多个属性当作key,也可以将tuple的元素当作key,但是有两种类型不能作为key:
- 没有复写hashCode方法,仅默认继承object的hashCode方法的pojo类
- 数组类型
dataStream.keyBy("someKey") // Key by field "someKey"
dataStream.keyBy(0) // Key by the first element of a Tuple
3.5 reduce
KeyedStream → DataStream
KeyedStream经过ReduceFunction后变成DataStream,主要的作用是对每个分区中的元素进行归约操作,每个分区只输出一个值,即归约结果。
DataStream<Student> flatMapSocketTextStream = socketTextStream.flatMap(new FlatMapFunction<String, Student>() {
@Override
public void flatMap(String value, Collector<Student> out) throws Exception {
String[] values = value.split(" ");
out.collect(new Student(values[0], values[1], values[2], Double.valueOf(values[3])));
}
});
DataStream<Student> reduceSteam = flatMapSocketTextStream
.keyBy("className")
.reduce((ReduceFunction<Student>) (s1, s2) -> s1.getScore() > s2.getScore() ? s1 : s2);
source:
zs nan a 60
ww nan a 70
ls nv b 90
ld nan b 85
ad nan a 80
flink:
3> {"name":"zs","gender":"nan","className":"a","score":60.0}
3> {"name":"ww","gender":"nan","className":"a","score":70.0}
1> {"name":"ls","gender":"nv","className":"b","score":90.0}
1> {"name":"ls","gender":"nv","className":"b","score":90.0}
3> {"name":"ad","gender":"nan","className":"a","score":80.0}
3.6 Fold
KeyedStream → DataStream
Fold与reduce的唯一区别在于Fold可以设置初始值。
注意:如果在一个时间窗口里进行窗口中的数据计算,相同的功能应该优先考虑ReduceFunction和FoldFunction,因为这些window函数是增量地对窗口中每一个到达的元素执行聚合操作,即一个窗口里永远只会保存一个聚合之后的结果,但一个windowFunction是获取了一个窗口中所有元素的一个迭代对象以及时间窗口的额外元信息。
3.7 Aggregations
KeyedStream → DataStream
聚合类算子包括:min,max,sum等
3.8 union & join
union 可以将多个DataFrame拼接在一起
join 将两个DataFrame join一起
共同学习,写下你的评论
评论加载中...
作者其他优质文章