Flink DataStream转换(翻译官方文档)

最近准备用flink对之前项目进行重构,这是一个有挑战(但我很喜欢)的工作。几个月过去了,flink社区比起我做技术调研那阵发生了很多变化(包括blink的版本回推),我这边的版本也由1.4->1.7.2。现在网上有很多大方向的解析(阿里的几次直播),也有大神对框架的深入解析。我准备实际使用中mark一些关键的知识点/api。以下就是我翻译的flink流计算DataStream Transformations,在流的构成转换中非常重要的知识点。


Operators

Operators 将一个或多个DataStream转换为新的DataStream。程序可以将多个转换组合成复杂的数据流拓扑。

本节介绍了基本转换,应用这些转换后的有效物理分区以及对Flink运算符链接的见解。

DataStream转换

转换名称描述
Map映射 DataStream→DataStream采用一个元素并生成一个元素。一个map函数,它将输入流的值加倍:
DataStream<Integer> dataStream = //... 
dataStream.map(new MapFunction<Integer, Integer>() { @Override public Integer map(Integer value) throws Exception { return 2 * value; } });

 

FlatMap DataStream→DataStream采用一个元素并生成零个,一个或多个元素。将句子分割为单词的flatmap函数:
dataStream.flatMap(new FlatMapFunction<String, String>() { @Override public void flatMap(String value, Collector<String> out) throws Exception { for(String word: value.split(" ")){ out.collect(word); } } });

 

Filter 过滤 DataStream→DataStream计算每个元素的布尔函数,并保留函数返回true的元素。过滤掉零值的过滤器:
dataStream.filter(new FilterFunction<Integer>() { @Override public boolean filter(Integer value) throws Exception { return value != 0; } });

 

KeyBy DataStream→KeyedStream逻辑上将流分区为不相交的分区。具有相同密钥的所有记录都分配给同一分区。在内部,keyBy()是使用散列分区实现的。指定键有多种方法。此转换返回KeyedStream,其中包括使用键控状态所需的KeyedStream
dataStream.keyBy("someKey") // Key by field "someKey" 
dataStream.keyBy(0) // Key by the first element of a Tuple
注意 如果出现以下情况,则类型不能成为关键:它是POJO类型,但不覆盖hashCode()方法并依赖于Object.hashCode()实现。它是任何类型的数组。
Reduce 减少 KeyedStream→DataStream密钥数据流上的“滚动”减少。将当前元素与最后一个减少的值组合并发出新值。 reduce函数,用于创建部分和的流:
keyedStream.reduce(new ReduceFunction<Integer>() { @Override public Integer reduce(Integer value1, Integer value2) throws Exception { return value1 + value2; } });

 

Fold 折叠 KeyedStream→DataStream具有初始值的键控数据流上的“滚动”折叠。将当前元素与最后折叠的值组合并发出新值。 折叠函数,当应用于序列(1,2,3,4,5)时,发出序列“start-1”,“start-1-2”,“start-1-2-3”,. ..
DataStream<String> result = keyedStream.fold("start", new FoldFunction<Integer, String>() { @Override public String fold(String current, Integer value) { return current + "-" + value; } });

 

Aggregations 聚合 KeyedStream→DataStream滚动聚合数据流上的聚合。min和minBy之间的差异是min返回最小值,而minBy返回该字段中具有最小值的元素(max和maxBy相同)。
keyedStream.sum(0); keyedStream.sum("key"); keyedStream.min(0); keyedStream.min("key"); keyedStream.max(0); keyedStream.max("key"); keyedStream.minBy(0); keyedStream.minBy("key"); keyedStream.maxBy(0); keyedStream.maxBy("key");

 

Window KeyedStream→WindowedStream可以在已经分区的KeyedStream上定义Windows。Windows根据某些特征(例如,在最后5秒内到达的数据)对每个密钥中的数据进行分组。有关窗口的完整说明,请参见windows。
dataStream.keyBy(0).window(TumblingEventTimeWindows.of(Time.seconds(5))); // Last 5 seconds of data

 

WindowAll DataStream→AllWindowedStreamWindows可以在常规DataStream上定义。Windows根据某些特征(例如,在最后5秒内到达的数据)对所有流事件进行分组。有关窗口的完整说明,请参见windows。警告:在许多情况下,这是非并行转换。所有记录将收集在windowAll运算符的一个任务中。
dataStream.windowAll(TumblingEventTimeWindows.of(Time.seconds(5))); // Last 5 seconds of data

 

Window Apply WindowedStream→DataStream AllWindowedStream→DataStream将一般功能应用于整个窗口。下面是一个手动求和窗口元素的函数。注意:如果您正在使用windowAll转换,则需要使用AllWindowFunction。
windowedStream.apply (new WindowFunction<Tuple2<String,Integer>, Integer, Tuple, Window>() { public void apply (Tuple tuple, Window window, Iterable<Tuple2<String, Integer>> values, Collector<Integer> out) throws Exception { int sum = 0; for (value t: values) { sum += t.f1; } out.collect (new Integer(sum)); } }); // applying an AllWindowFunction on non-keyed window stream 
allWindowedStream.apply (new AllWindowFunction<Tuple2<String,Integer>, Integer, Window>() { public void apply (Window window, Iterable<Tuple2<String, Integer>> values, Collector<Integer> out) throws Exception { int sum = 0; for (value t: values) { sum += t.f1; } out.collect (new Integer(sum)); } });

 

Window Reduce WindowedStream→DataStream将功能减少功能应用于窗口并返回减少的值。
windowedStream.reduce (new ReduceFunction<Tuple2<String,Integer>>() { public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) throws Exception { return new Tuple2<String,Integer>(value1.f0, value1.f1 + value2.f1); } });

 

Window Fold WindowedStream→DataStream将功能折叠功能应用于窗口并返回折叠值。示例函数应用于序列(1,2,3,4,5)时,将序列折叠为字符串“start-1-2-3-4-5”:
windowedStream.fold("start", new FoldFunction<Integer, String>() { public String fold(String current, Integer value) { return current + "-" + value; } });

 

Aggregations on windows WindowedStream→DataStream聚合窗口的内容。min和minBy之间的差异是min返回最小值,而minBy返回该字段中具有最小值的元素(max和maxBy相同)。
windowedStream.sum(0); windowedStream.sum("key"); windowedStream.min(0); windowedStream.min("key"); windowedStream.max(0); windowedStream.max("key"); windowedStream.minBy(0); windowedStream.minBy("key"); windowedStream.maxBy(0); windowedStream.maxBy("key");

 

Union DataStream *→DataStream两个或多个数据流的联合,创建包含来自所有流的所有元素的新流。注意:如果将数据流与其自身联合,则会在结果流中获取两次元素。
dataStream.union(otherStream1, otherStream2, ...);

 

Window Join DataStream,DataStream→DataStream在给定密钥和公共窗口上连接两个数据流。
dataStream.join(otherStream) .where(<key selector>).equalTo(<key selector>) .window(TumblingEventTimeWindows.of(Time.seconds(3))) .apply (new JoinFunction () {...});

 

Interval Join KeyedStream,KeyedStream→DataStream在给定的时间间隔内使用公共密钥连接两个键控流的两个元素e1和e2,以便e1.timestamp + lowerBound <= e2.timestamp <= e1.timestamp + upperBound/
// this will join the two streams so that
 // key1 == key2 && leftTs - 2 < rightTs < leftTs + 2 
keyedStream.intervalJoin(otherKeyedStream) .between(Time.milliseconds(-2), Time.milliseconds(2)) // lower and upper bound 
.upperBoundExclusive(true) // optional 
.lowerBoundExclusive(true) // optional 
.process(new IntervalJoinFunction() {...});
Window CoGroup DataStream,DataStream→DataStream在给定密钥和公共窗口上对两个数据流进行Cogroup。
dataStream.coGroup(otherStream) .where(0).equalTo(1) .window(TumblingEventTimeWindows.of(Time.seconds(3))) .apply (new CoGroupFunction () {...});

 

Connect 连接 DataStream,DataStream→ConnectedStreams“连接”两个保留其类型的数据流。连接允许两个流之间的共享状态。DataStream<Integer> someStream = //... DataStream<String> otherStream = //... ConnectedStreams<Integer, String> connectedStreams = someStream.connect(otherStream);
CoMap,CoFlatMap ConnectedStreams→DataStream类似于连接数据流上的map和flatMapconnectedStreams.map(new CoMapFunction<Integer, String, Boolean>() { @Override public Boolean map1(Integer value) { return true; } @Override public Boolean map2(String value) { return false; } }); connectedStreams.flatMap(new CoFlatMapFunction<Integer, String, String>() { @Override public void flatMap1(Integer value, Collector<String> out) { out.collect(value.toString()); } @Override public void flatMap2(String value, Collector<String> out) { for (String word: value.split(" ")) { out.collect(word); } } });
Split 拆分 DataStream→SplitStream根据某些标准将流拆分为两个或更多个流。SplitStream<Integer> split = someDataStream.split(new OutputSelector<Integer>() { @Override public Iterable<String> select(Integer value) { List<String> output = new ArrayList<String>(); if (value % 2 == 0) { output.add("even"); } else { output.add("odd"); } return output; } });
Select选择 SplitStream→DataStream从拆分流中选择一个或多个流。SplitStream<Integer> split; DataStream<Integer> even = split.select("even"); DataStream<Integer> odd = split.select("odd"); DataStream<Integer> all = split.select("even","odd");
Iterate迭代 DataStream→IterativeStream→DataStream通过将一个运算符的输出重定向到某个先前的运算符,在流中创建“反馈”循环。这对于定义不断更新模型的算法特别有用。以下代码以流开头并连续应用迭代体。大于0的元素将被发送回反馈通道,其余元素将向下游转发。有关完整说明,请参阅迭代IterativeStream<Long> iteration = initialStream.iterate(); DataStream<Long> iterationBody = iteration.map (/*do something*/); DataStream<Long> feedback = iterationBody.filter(new FilterFunction<Long>(){ @Override public boolean filter(Long value) throws Exception { return value > 0; } }); iteration.closeWith(feedback); DataStream<Long> output = iterationBody.filter(new FilterFunction<Long>(){ @Override public boolean filter(Long value) throws Exception { return value <= 0; } });
Extract Timestamps DataStream→DataStream从记录中提取时间戳,以便使用使用事件时间语义的窗口。查看活动时间stream.assignTimestamps (new TimeStampExtractor() {...});

以下转换可用于元组的数据流:

转换名称描述
Project DataStream→DataStream从元组中选择字段的子集DataStream<Tuple3<Integer, Double, String>> in = // [...] DataStream<Tuple2<String, Integer>> out = in.project(2,0);

物理分区

Flink还通过以下函数对转换后的精确流分区进行低级控制(如果需要)。

转型描述
Custom partitioning自定义分区 DataStream→DataStream使用用户定义的分区程序为每个元素选择目标任务。dataStream.partitionCustom(partitioner, "someKey"); dataStream.partitionCustom(partitioner, 0);
Random partitioning随机分区 DataStream→DataStream根据均匀分布随机分配元素。dataStream.shuffle();
Rebalancing (Round-robin partitioning) 重新平衡(循环分区) DataStream→DataStream分区元素循环,每个分区创建相等的负载。在存在数据偏斜时用于性能优化。dataStream.rebalance();
Rescaling重新调整 DataStream→DataStream分区元素,循环,到下游操作的子集。如果您希望拥有管道,例如,从源的每个并行实例扇出到多个映射器的子集以分配负载但又不希望发生rebalance()会产生完全重新平衡,那么这非常有用。这将仅需要本地数据传输而不是通过网络传输数据,具体取决于其他配置值,例如TaskManagers的插槽数。上游操作发送元素的下游操作的子集取决于上游和下游操作的并行度。例如,如果上游操作具有并行性2并且下游操作具有并行性6,则一个上游操作将元件分配到三个下游操作,而另一个上游操作将分配给其他三个下游操作。另一方面,如果下游操作具有并行性2而上游操作具有并行性6,则三个上游操作将分配到一个下游操作,而其他三个上游操作将分配到另一个下游操作。在不同并行度不是彼此的倍数的情况下,一个或多个下游操作将具有来自上游操作的不同数量的输入。请参阅此图以获取上例中连接模式的可视化:dataStream.rescale();
Broadcasting 广播 DataStream→DataStream向每个分区广播元素。dataStream.broadcast();

任务链和资源组

链接两个后续转换意味着将它们共同定位在同一个线程中以获得更好的性能。如果可能的话,Flink默认链操作符(例如,两个后续的映射转换)。如果需要,API可以对链接进行细粒度控制:

使用StreamExecutionEnvironment.disableOperatorChaining()如果要禁用整个工作链。对于更细粒度的控制,可以使用以下功能。请注意,这些函数只能在DataStream转换后立即使用,因为它们引用了前一个转换。例如,您可以使用someStream.map(...).startNewChain(),但不能使用someStream.startNewChain()

资源组是Flink中的一个插槽,请参阅 插槽。如果需要,您可以在单独的插槽中手动隔离操作员

转型描述
Start new chain从这个运算符开始,开始一个新的链。两个映射器将被链接,并且过滤器将不会链接到第一个映射器。someStream.filter(...).map(...).startNewChain().map(...);
Disable chaining不要链接地图运算符someStream.map(...).disableChaining();
Set slot sharing group设置操作的插槽共享组。Flink将把具有相同插槽共享组的操作放入同一个插槽,同时保留其他插槽中没有插槽共享组的操作。这可用于隔离插槽。如果所有输入操作都在同一个插槽共享组中,则插槽共享组将继承输入操作。默认插槽共享组的名称为“default”,可以通过调用slotSharingGroup(“default”)将操作明确地放入此组中。someStream.filter(...).slotSharingGroup("name");

专有名词很多,内容会随着我逐渐了解进行修改。我觉得最直观的还是代码示例。在实际使用中加深理解,日后如果有机会,也会对一两个api写下理解/使用。

顺带做个预测,重构代码转换中前3个api占比至少在百分之70以上。


原文连接 https://ci.apache.org/projects/flink/flink-docs-release-1.7/dev/stream/operators/index.html#physical-partitioning

3.17更新:这周发现了一个翻译好的文档地址https://flink.sojb.cn/,其完整性和正确性比我翻译好太多,故这方面不再更新。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值