Flink 流处理api之transform算子

1,293 阅读4分钟

欢迎关注我的个人博客学习更多知识

transform

作用:将Soure数据(源数据)进行转换计算为需要的数据

常用函数

map

map算子和python中的map类似,python中是把数据转换为lambda表达式中的数据,而flink中的map更广泛一些,通过new一个 Mapfunction,自定义map()方法规定转换流程, 把一个数据类型(input)转换为另一个数据类型(output) 格式如下

dataStream.map(new Mapfunction<input,output>(){
	@Override
	map(input){xxx};
})

通过画图可以更好理解 image.png

矩形变成了椭圆,但是颜色没变(逻辑没变)

flatMap

flatMap 扁平化算子:把输入input类型转化为output类型输出,与map不同,flatmap输出多个output类型 具个例子 字符串“hello,word” 以Tuple2(“hello”,1)、Tuple2(“word”,1)形式输出

inputDataStream.flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() {
            @Override
            public void flatMap(String input, Collector<Tuple2<String, Integer>> collector) throws Exception {
                String[] words = input.split(",");
                for (String word : words) {
                    collector.collect(new Tuple2<>(word, 1));
                }
            }
        });

filter

filter算子把input类型输入数据过滤出来 。为true留下来,false过滤掉 图示如下 image.png

keyby(分组)

DataStream → KeyedStream:逻辑地将一个流拆分成不相交的分区,每个分区包含具有相同 key 的元素,在内部以 hash 的形式实现的。 image.png

使用 dataStream.keyby(param)

param:数据字段下标 默认从0开始 也可以输入id的字段,就会按照id分流

滚动聚合算子(rolling Aggregation)

  • sum :求和
  • max : 选择每条流的最大值
  • min : 选择每条流的最小值
  • minby : 针对 keyedStream中的某个字段数据进行选择最小值
  • maxby : 针对 keyedStream中的某个字段数据进行选择最大值

reduce(复杂聚合)

KeyedStream → DataStream:合并当前的元素和上次聚合的结果,产生一个新的值,返回的流中包含每一次聚合的结果,而不是只返回最后一次聚合的最终结果。 案例:根据传感器id传来的数据比较上一次时间戳的温度,选择最大温度的时间戳数据

import com.chengyuyang.apitest.SensorReading;
import com.chengyuyang.apitest.SourceFromCustom;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;

public class Transform_keyed_Reduce {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        // 数据源为自定义产生的传感器数据
        DataStreamSource<SensorReading> inputDataStream = env.addSource(new SourceFromCustom.CustomSource());
        //根据传感器id传来的数据比较上一次时间戳的温度,选择最大温度的时间戳数据
        SingleOutputStreamOperator<SensorReading> resultDataStream = inputDataStream.keyBy("id")
                .reduce(new CustomReduceFunction());
        resultDataStream.print();
        env.execute();
    }

    public static class CustomReduceFunction implements ReduceFunction<SensorReading> {
        @Override
        public SensorReading reduce(SensorReading sensorReading, SensorReading input) throws Exception {
            String id = sensorReading.getId();
            Long timestamp = input.getTimestamp();
            //按照时间戳选温度最大的值
            double temperature = Math.max(sensorReading.getTemperature(), input.getTemperature());
            return new SensorReading(id, timestamp, temperature);
        }
    }
}

split 和 select (分流)

split

DataStream → SplitStream:根据某些特征把一个 DataStream 拆分成两个或者多个 DataStream 图示如下

image.png

select

SplitStream→DataStream:从一个 SplitStream 中获取一个或者多个DataStream

图示如下 image.png

案例

根据传感器的温度,以60度为标准,大于等于60度为high流,其他为low流

import org.apache.flink.shaded.guava18.com.google.common.collect.Lists;
import org.apache.flink.streaming.api.collector.selector.OutputSelector;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SplitStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import com.chengyuyang.apitest.SensorReading;
import com.chengyuyang.apitest.SourceFromCustom;

public class Transform_Split_Select {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStreamSource<SensorReading> inputDatStream = env.addSource(new SourceFromCustom.CustomSource());
        // 按照温度60标准进行分流 split里面其实是实现的select(选择)操作
        SplitStream<SensorReading> splitStream = inputDatStream.split(new OutputSelector<SensorReading>() {
            @Override
            public Iterable<String> select(SensorReading sensorReading) {
                Double temperature = sensorReading.getTemperature();
                if (temperature >= 60) {
                    return Lists.newArrayList("high");
                } else {
                    return Lists.newArrayList("low");
                }
            }
        });
        //SplitStream→DataStream操作 select变量可以为多个 上面两种split 可以select成3种DataStream流
        DataStream<SensorReading> high = splitStream.select("high");
        DataStream<SensorReading> low = splitStream.select("low");
        DataStream<SensorReading> all = splitStream.select("high", "low");

        high.print("high").setParallelism(1);
        low.print("low").setParallelism(1);
        all.print("all").setParallelism(1);
        env.execute();
    }
}

结果如下 image.png

connect 和 comap

connect(一国两制)

DataStream,DataStream → ConnectedStreams:连接两个流为ConnectedStreams流,但是保持他们各种的数据类型不发生变化,内部两个流相互独立,输入数据类型可以一样也可以不一样

图示如下 image.png

comap coflatmap

ConnectedStreams → DataStream 功能同map和 flatMap 一样,只不过由于connect类的两个流的数据类型不同 要分别对里面的流进行map 和 flatMap处理,最终结果可一样可不一样

案例

按照split 和 select案例的分流对高温加上warning标签 正常温度数据输出

部分代码

ConnectedStreams<Tuple2<String, Double>, SensorReading> connectDataStream = highDataStream.connect(lowDataStream);
        SingleOutputStreamOperator<Object> resultDataStream = connectDataStream.map(new CoMapFunction<Tuple2<String, Double>, SensorReading, Object>() {
            @Override
            public Object map1(Tuple2<String, Double> input) throws Exception {
                // 处理高温数据
                return new Tuple3<>(input.f0, input.f1, "warnning");
            }

            @Override
            public Object map2(SensorReading input) throws Exception {
                // 处理正常温度数据
                return new Tuple3<>(input.getId(), input.getTimestamp(), input.getTemperature());
            }
        });

union

DataStream → DataStream 对两个或者两个以上的DataStream进行union操作,产生一个包含所有DataStream元素的新DataStream。注意:如果你将一个DataStream跟它自己做union操作,在新的DataStream中,你将看到每一个元素都出现两次 图示如下 image.png

Connect 与 Union 区别

  • Union 之前两个流的类型必须是一样,Connect 可以不一样
  • Connect 在之后的 coMap中可以再去调整成为一样的,也可以不一样的
  • Connect 只能操作两个流,Union 可以操作多个

案例

按照split 和 select案例的分流进行union,对高温加上warning标签 正常温度数据输出

部分代码

DataStream<SensorReading> unionDataStream = high.union(low);
        SingleOutputStreamOperator<Tuple3<String, Long, Object>> resultDataStream = unionDataStream.map(new MapFunction<SensorReading, Tuple3<String, Long, Object>>() {
            @Override
            public Tuple3<String, Long, Object> map(SensorReading input) throws Exception {
                if (input.getTemperature() >= 60) {
                    return new Tuple3<String, Long, Object>(input.getId(), input.getTimestamp(), "warnning");
                } else {
                    return new Tuple3<String, Long, Object>(input.getId(), input.getTimestamp(), input.getTemperature());
                }
            }
        });

本文转载于我的个人博客Flink 流处理api之transform算子 遵循 CC 4.0 BY-SA 版权协议

欢迎交流学习

个人博客

csdn主页