【flink学习笔记】【5】转换算子Transform

1. 基本转换算子

1.1 映射 MAP

1.1.1 自定义mapper

自定义类mapper,实现MapFunction接口

public static class MyMapper implements MapFunction<Event, String > {
    @Override
    public String  map(Event value) throws Exception {
        return value.user;
    }
}

对source进行转换:

SingleOutputStreamOperator<String> result = stream.map(new MyMapper());

1.1.2 匿名类

//匿名类
SingleOutputStreamOperator<String> result2 = stream.map(new MapFunction<Event, String>() {
    @Override
    public String map(Event event) throws Exception {
        return event.user;
    }
});

1.1.3 lambda表达式

//3.lambda表达式
 SingleOutputStreamOperator<String> result3 = stream.map(data -> data.user);
 result3.print();

1.2 过滤 filter

1.2.1 自定义filter 方法

public static class MyFilter implements FilterFunction<Event>{
        @Override
        public boolean filter(Event event) throws Exception {
            return event.user.equals("GENGYUNZHE");
        }
    }

1.2.2 匿名类

 // 2. 匿名类
SingleOutputStreamOperator<Event> result2 = stream.filter(new FilterFunction<Event>() {
    @Override
    public boolean filter(Event event) throws Exception {
        return event.user.equals("GENGYUNZHE");
    }
});

1.2.3 LAMBDA表达式

// 3. lambda表达式
 SingleOutputStreamOperator<Event> result3 = stream.filter(data -> data.user.equals("GENGYUNZHE"));

1.3 flatMap 扁平映射

1.3.1 自定义方法

数据流的整体拆开打散,每个元素map转换,不是一对一的,可一对多。

public static class MyFlatMap implements FlatMapFunction<Event,String>{
        @Override
        public void flatMap(Event o, Collector<String> out) throws Exception {
            out.collect(o.user);
            out.collect(o.url);
            out.collect(o.timestamp.toString());
        }
    }

在这里插入图片描述

1.3.2 lambda表达式

//2 lambda
 stream.flatMap((Event value,Collector<String> out) ->{
     if (value.user.equals("GENGYUNZHE")){
         out.collect(value.user);
     }
     else {
         out.collect(value.user);
         out.collect(value.url);
         out.collect(value.timestamp.toString());
     }
 }).returns(new TypeHint<String>() {}).print();

1.3.3 泛型擦除

2. 聚合算子 aggregation

2.1 按键分区(keyby)

2.1.1 简单聚合

  • max返回最大值
  • maxBy 把最大值对应的元素全部返回
// 按键分组后聚合,提取最近一次访问的用户
 stream.keyBy(new KeySelector<Event, String>() {
     @Override
     public String getKey(Event event) throws Exception {
         return event.user;
     }
 }).max("timestamp").print("max:");

流式处理,来一条处理一条。
在这里插入图片描述
lambda表达式

 stream.keyBy(data -> data.user).maxBy("timestamp").print();

2.1.2 规约聚合 reduce

当前最活跃用户

//1.统计每个用户的访问频次
SingleOutputStreamOperator<Tuple2<String, Long>> clickByUser = stream.map(new MapFunction<Event, Tuple2<String, Long>>() {
       @Override
       public Tuple2<String, Long> map(Event event) throws Exception {
           return Tuple2.of(event.user, 1L);
       }
   }).keyBy(data -> data.f0).reduce(new ReduceFunction<Tuple2<String, Long>>() {
       @Override
       public Tuple2<String, Long> reduce(Tuple2<String, Long> stringLongTuple2, Tuple2<String, Long> t1) throws Exception {
           return Tuple2.of(stringLongTuple2.f0, stringLongTuple2.f1 + t1.f1);
       }
   });
 // 2.根据当前个数选取最活跃用户
SingleOutputStreamOperator<Tuple2<String, Long>> result = clickByUser.keyBy(data -> "key").reduce(new ReduceFunction<Tuple2<String, Long>>() {
    @Override
    public Tuple2<String, Long> reduce(Tuple2<String, Long> stringLongTuple2, Tuple2<String, Long> t1) throws Exception {
        return stringLongTuple2.f1 > t1.f1 ? stringLongTuple2 : t1;
    }
});

3. UDF 自定义函数

flink datastream API编程风格一致的:基于datastream调用一个方法:表示转换操作,方法需要传参,都需要实现一个接口——
源算子需要实现 sourcefunction接口, map算子需要实现 mapfunction接口
reduce算子需要实现reducefunction接口。

SAM 抽象方法接口:

  1. 函数类
  2. 匿名类
  3. lambda表达式
  4. 富函数类
    a. 获取运行环境的上下文,生命周期方法(对于并行子任务只会调用一次),实际工作方法,每一条数据都会触发一次。
    b. open() close()
    c.因为生命周期方法等,无法使用lambda表达式

//自定义富函数类
public static class MyRichMapper extends RichMapFunction<Event, Integer>{
    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        System.out.println("open生命周期调用"+ getRuntimeContext().getIndexOfThisSubtask()+"号任务启动");
    }

    @Override
    public void close() throws Exception {
        super.close();
        System.out.println("open生命周期调用"+ getRuntimeContext().getIndexOfThisSubtask()+"号任务结束");
    }

    @Override
    public Integer map(Event event) throws Exception {
        return event.url.length();
    }
}

4. 物理分区

4.1 轮询分区

keyby是逻辑分区,物理分区控制分区策略,将流中的数据重新分配,
应用场景:数据倾斜,负载不够均衡


  //1. shuffle随机分区,均匀分布
  stream.shuffle().print().setParallelism(4);

  //2. 轮询分区(顺序1234,打印顺序不是)
  stream.rebalance().print().setParallelism(4);

4.2 rescale 重缩放分区

上游两个并行子任务,下游4个并行子任务,分成几组在组内进行轮询发牌
优点:相较于rebalance,避免了跨 taskmanager减少网络传输消耗。rebalance上下游会建立笛卡尔积链接。

rebalance()和rescale()的根本区别在于任务之间连接的机制不同。rebalance()将会针对所有发送者任务和所有接收者任务之间建立通信通道,而rescale()仅仅针对每一个任务和下游算子的一部分子并行任务之间建立通信通道。
在这里插入图片描述

// 3. rescale重缩放分区
 env.addSource(new RichParallelSourceFunction<Integer>() {
     @Override
     public void run(SourceContext<Integer> sourceContext) throws Exception {
         for (int i=0;i<10;i++){
             //子任务索引号发对应奇偶数到并行分区
             if(i % 2==getRuntimeContext().getIndexOfThisSubtask()){
                 sourceContext.collect(i);
             }

         }
     }

     @Override
     public void cancel() {

     }
 }).setParallelism(2).rescale().print().setParallelism(4);

4.3 广播

把当前的一个数据分发到下游所有的并行子任务。
并行度4

stream.broadcast().print().setParallelism(4);

每个并行子任务都会执行
在这里插入图片描述

4.4 全局分区

作用:将所有的输入流数据都发送到下游算子的第一个并行任务中去。这个操作需要很谨慎,因为将所有数据发送到同一个task,将会对应用程序造成很大的压力。

stream.global().print().setParallelism(4);

并行度失效。
在这里插入图片描述

4.5 自定义重分区

作用:使用自定义分区策略实现分区逻辑以及定义针对流的哪个字段或者key进行分区。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值