我是Flink的新手,我使用的是DataSet API。在作为最后一个阶段的一大堆处理之后,我需要通过将其除以其最大值来规范化其中一个值。所以,我使用.max()
运算符来获取最大值,然后我将结果作为构造函数的参数传递给MapFunction。
这可行,但所有处理都执行两次。执行一个作业以查找最大值,然后执行另一个作业以创建最终结果(从头开始执行)...是否有任何解决方法只执行一次整个数据流?
final List<Tuple6<...>> maxValues = result.max(2).collect();
assert maxValues.size() == 1;
result.map(new NormalizeAttributes(maxValues.get(0))).writeAsCsv(...)
@FunctionAnnotation.ForwardedFields("f0; f1; f3; f4; f5")
@FunctionAnnotation.ReadFields("f2")
private static class NormalizeAttributes implements MapFunction<Tuple6<...>, Tuple6<...>> {
private final Tuple6<...> maxValues;
public NormalizeAttributes(Tuple6<...> maxValues) {
this.maxValues = maxValues;
}
@Override
public Tuple6<...> map(Tuple6<...> value) throws Exception {
value.f2 /= maxValues.f2;
return value;
}
}
答案 0 :(得分:0)
collect()
会立即触发程序执行,直至collect()
请求的数据集。如果您稍后再次致电env.execute()
或collect()
,则会第二次执行该程序。
除了执行的副作用外,使用collect()
将值分配给后续转换还有一个缺点,即数据会传输到客户端,然后再传回集群。 Flink提供所谓的广播变量,将DataSet
作为侧输入发送到另一个转换中。
在程序中使用Broadcast变量如下所示:
DataSet maxValues = result.max(2);
result
.map(new NormAttrs()).withBroadcastSet(maxValues, "maxValues")
.writeAsCsv(...);
NormAttrs
函数如下所示:
private static class NormAttr extends RichMapFunction<Tuple6<...>, Tuple6<...>> {
private Tuple6<...> maxValues;
@Override
public void open(Configuration config) {
maxValues = (Tuple6<...>)getRuntimeContext().getBroadcastVariable("maxValues").get(1);
}
@Override
public PredictedLink map(Tuple6<...> value) throws Exception {
value.f2 /= maxValues.f2;
return value;
}
}
您可以在documentation中找到有关广播变量的更多信息。