Flink执行两次数据流

时间:2016-08-23 08:14:27

标签: apache-flink

我是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;
    }
}

1 个答案:

答案 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中找到有关广播变量的更多信息。