为了账号安全,请及时绑定邮箱和手机立即绑定

Flink-demo速成与常见算子

2019.07.01 22:04 7048浏览

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:

  1. 没有复写hashCode方法,仅默认继承object的hashCode方法的pojo类
  2. 数组类型
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一起

点击查看更多内容

本文原创发布于慕课网 ,转载请注明出处,谢谢合作

1人点赞

若觉得本文不错,就分享一下吧!

评论

相关文章推荐

正在加载中
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消