Flink_02_算子(个人总结)

    声明: 1. 本文为我的个人复习总结, 并那种从零基础开始普及知识 内容详细全面, 言辞官方的文章
              2. 由于是个人总结, 所以用最精简的话语来写文章
              3. 若有错误不当之处, 请指出

Flink程序的组成结构:

  1. Source: 数据输入

  2. Transform算子: 转换算子

  3. Sink: 数据输出

    ​ Flink没有Spark中类似于foreach的方法让用户进行遍历操作, 所有对外的输出操作都需要利用Sink完成

    ​ 最好要有Sink(充当行动算子), 不然转换算子有时并不会触发计算

对于User<Tuple<String,String>>类型的返回值(两层泛型嵌套), 就不要用lambda简写了, 因为运行时类型被擦除了

.socketTextStream( ) 并行度一定是1

Transform 转换算子:

  1. map

  2. flatMap

    用的是out.collect方式, 可以输出任意个参数

  3. filter

  4. keyBy(相当于group by, 但它是分区, 一组数据占一个分区)

    1. .keyBy(“itemId”) 得到的返回值K-V对中的value是<key, 元素本身>
    2. .keyBy(0) 按第几个字段进行分组, 等效于第一种方式
    3. .keyBy(t->t.getItemId( )) 得到的返回值K-V对中的value是元素本身

    如果想keyBy多个字段,那就只能选择前两种方式了, .keyBy(“channel”,“behavior”)

  5. shuffle

    将数据打散后随机(不是按hash(key)%分区数量)分布到下游

  6. split 和 select

    先切分, 后选择

    案例: 将温度数据拆分成high流 和 low流

    SplitStream<SensorReading> splitStream = dataStream.split(new OutputSelector<SensorReading>( ) {
        @Override
        public Iterable<String> select(SensorReading value) {
            return (value.getTemperature( ) > 30) ? Collections.singletonList("high") : Collections.singletonList("low");
        }
    });
    
    DataStream<SensorReading> highTempStream = splitStream.select("high");
    DataStream<SensorReading> lowTempStream = splitStream.select("low");
    DataStream<SensorReading> allTempStream = splitStream.select("high", "low");
    
  7. connect 和 CoMapFunction

    先将两个流(数据类型可以不同)进行混流合并, 再分别map

    示例:

    ConnectedStreams<Tuple2<String, Double>, SensorReading> connectedStreams = warningStream.connect(lowTempStream);
    
    DataStream<Object> resStream = connectedStreams.map(new CoMapFunction<Tuple2<String, Double>, SensorReading, Object>( ) {
        @Override
        public Object map1(Tuple2<String, Double> value) throws Exception {
            return new Tuple3<>(value.f0, value.f1, "warning");
        }
    
    
        @Override
        public Object map2(SensorReading value) throws Exception {
            return new Tuple2<>(value.getId( ), "healthy");
        }
    });
    
  8. union

    多个流(数据类型得相同)进行混流合并

    参数为可变参数…


process 传入自定义的ProcessFunction


针对KeyedStream中每一个key的支流做聚合

  • sum

    每个分区都会产生一条数据, 而不是只返回最终结果

    如:

    0> 1

    1> 3

    2> 5

    3> 9

    最终sum为5

    sum(String field) 指定字段名称

    sum(int position) 是给元组用的, position从0开始算

  • min

  • max

    .max(“score”), 每条数据的score值显示目前为止遇到的最大score, 其他字段还用自己的原本的值

    原数据:
    	name 	score
    	 小明   	   80
             小红   	  100
             小花   	   60 
    
    .max("score"):
    	name 	score
    	 小明   	   80
             小红   	  100
             小花   	  100  // score被取代
    
  • minBy

  • maxBy

    .maxBy(“score”), 每条数据的score值显示目前为止遇到的最大score, 其他字段值用 最大score的这条数据对应字段值 进行代替

    原数据:
    	name 	score
    	 小明   	   80
             小红   	  100
             小花   	   60 
    
    .maxBy("score"):
    	name 	score
    	 小明   	   80
             小红   	  100
             小红   	  100  // score被取代, name也被取代
    
  • reduce 需要先进行.keyBy, 因为如果不.keyBy就会发生全局的数据聚合, 就只能有一个reduce任务, 所以需要先.keyBy尽量优化下

函数:

  1. 普通函数

    MapFunction, FlatMapFunction, FilterFunction, SourceFunction, SinkFunction

  2. 富函数

    可以获取运行环境的上下文, 并拥有一些生命周期方法

    RichMapFunction, RichFlatMapFunction, RichFilterFunction, RichSinkFunction

    生命周期方法:

    1. open( ) 初始化方法

    2. close( ) 清理释放工作

    3. getRuntimeContext( ) 得到RuntimeContext, 可以获取一些信息, 比如watemark, window, 侧输出流, 处理时间, state状态等

算子总结:

  1. ProcessFunction可以使用 侧输出流, 生命周期方法,状态,注册定时事件

  2. 富函数可以使用生命周期方法,状态

  3. 普通函数不能使用侧输出流, 生命周期方法,状态,注册定时事件

所以, 侧输出流仅有ProcessFunction可以使用

ProcessFunction是啥都能做, 是万能的底层API, 但是使用起来较麻烦

接口的继承关系上, ProcessFunction(子孙) -> RichFunction -> Function(祖先)

子类的功能对父类进行了拓展, 故子类的功能更丰富

DataStream支持的常用 Source & Sink

Source:

​ Kafka, Netty

Sink:

​ Kafka, ElasticSearch

​ Redis, HDFS, Hive, Flume

​ 自定义MyBatisPlus输出到(Phoenix, ClickHouse, MySQL)

KafkaSource:

  1. 动态发现分区

    在消费过程中, 每隔一段时间就去检查一下是否有新的分区创建

  2. 从kafka数据源生成watermark

    kafkaSourceFunction.assignTimestampsAndWatermarks( WatermarkStrategy.forBoundedOutOfOrderness(Time.seconds(1)));
    
  3. 设置空闲等待

    问题:

    ​ watermark在上下游分区间进行传递时, 可能某个上游分区始终没有数据(watermark初始为Long.MIN_VALUE), 那么下游watermark 就始终没法更新

    解决:

    ​ 可以使用设置withIdleness时间; 若此时间内 上游分区始终接收不到新数据, 则下游计算watermark时就不管这个上游分区了

    kafkaSourceFunction.assignTimestampsAndWatermarks(
                    WatermarkStrategy.forBoundedOutOfOrderness(Time.seconds(1)).withIdleness(Time.seconds(1))
    );
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值