欢迎关注我的个人博客学习更多知识
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};
})
通过画图可以更好理解
矩形变成了椭圆,但是颜色没变(逻辑没变)
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过滤掉
图示如下
keyby(分组)
DataStream → KeyedStream:逻辑地将一个流拆分成不相交的分区,每个分区包含具有相同 key 的元素,在内部以 hash 的形式实现的。
使用 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 图示如下
select
SplitStream→DataStream:从一个 SplitStream 中获取一个或者多个DataStream
图示如下
案例
根据传感器的温度,以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();
}
}
结果如下
connect 和 comap
connect(一国两制)
DataStream,DataStream → ConnectedStreams:连接两个流为ConnectedStreams流,但是保持他们各种的数据类型不发生变化,内部两个流相互独立,输入数据类型可以一样也可以不一样
图示如下
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中,你将看到每一个元素都出现两次
图示如下
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 版权协议