Apache Flink - 从另一个Stream的MapFunction

时间:2018-04-21 17:44:26

标签: apache-flink flink-streaming

我有一个基于Apache Flink的流媒体应用程序,具有以下设置:

  • 数据源:每分钟生成一次数据。
  • 使用CountWindow的窗口流,大小= 100,slide = 1(滑动计数窗口)。
  • ProcessWindowFunction对窗口中的数据应用一些计算(比如F(x))。
  • 数据接收器消耗输出流

这很好用。现在,我想让用户提供一个函数G(x)并将其应用于Window中的当前数据并实时将输出发送给用户

我不是在问如何应用任意函数G(x) - 我正在使用动态脚本来做到这一点。我问的是如何从另一个流的地图函数中访问窗口中的缓冲数据。

一些代码澄清

DataStream<Foo> in  = .... // source data produced every minute
    in
       .keyBy(new MyKeySelector())
       .countWindow(100, 1)
       .process(new MyProcessFunction())
       .addSink(new MySinkFunction())

// The part above is working fine. Note that windowed stream created by countWindow() function above has to maintain internal buffer. Now the new requirement

DataStream<Function> userRequest  = .... // request function from user

userRequest.map(new MapFunction<Function, FunctionResult>(){
   public FunctionResult map(Function Gx) throws Exception {
         Iterable<Foo> windowedDataFromAbove = // HOW TO GET THIS???
         FunctionResult result = Gx.apply(windowedDataFromAbove);
         return result;

   }

})

2 个答案:

答案 0 :(得分:0)

连接两个流,然后使用CoProcessFunction。获取函数流的方法调用可以将它们应用于其他方法调用窗口中的内容。

如果你想广播功能,那么你需要使用Flink 1.5(它支持连接键控和广播流),或者使用一些直升机特技创建一个可以同时包含Foo和Function类型的流,通过适当复制函数(和密钥代)来模拟广播。

答案 1 :(得分:0)

假设Fx在飞行中汇总传入的foos并且Gx处理了一个窗口的值得注意的foos,你应该能够达到你想要的效果:

DataStream<Function> userRequest  = .... // request function from user
Iterator<Function> iter = DataStreamUtils.collect(userRequest);
Function Gx = iter.next();

DataStream<Foo> in  = .... // source data
 .keyBy(new MyKeySelector())
 .countWindow(100, 1)
 .fold(new ArrayList<>(), new MyFoldFunc(), new MyProcessorFunc(Gx))
 .addSink(new MySinkFunction())

折叠功能(一旦到达就对输入数据进行操作)可以这样定义:

private static class MyFoldFunc implements FoldFunction<foo, Tuple2<Integer, List<foo>>> {
    @Override
    public Tuple2<Integer, List<foo>> fold(Tuple2<Integer, List<foo>> acc, foo f) {
        acc.f0 = acc.f0 + 1; // if Fx is a simple aggregation (count)
        acc.f1.add(foo);
        return acc;
    }
}

处理器功能可以是这样的:

public class MyProcessorFunc
    extends ProcessWindowFunction<Tuple2<Integer, List<foo>>, Tuple2<Integer, FunctionResult>, String, TimeWindow> {

    public MyProcessorFunc(Function Gx) {
        super();
        this.Gx = Gx;
    }

    @Override
    public void process(String key, Context context,
                        Iterable<Tuple2<Integer, List<foo>> accIt,
                        Collector<Tuple2<Integer, FunctionResult>> out) {
        Tuple2<Integer, List<foo> acc = accIt.iterator().next();
        out.collect(new Tuple2<Integer, FunctionResult>(
            acc.f0, // your Fx aggregation
            Gx.apply(acc.f1), // your Gx results
        ));
    }
}

请注意,默认情况下,fold \ reduce函数不会在内部缓冲元素。我们在这里使用fold来计算实时指标,并创建窗口项列表。

如果您有兴趣在翻滚窗口(不滑动)上应用Gx,您可以在管道中使用翻滚窗口。要计算滑动计数,您可以使用管道的另一个分支来计算滑动计数(不应用Gx)。这样,您不必每个窗口保留100个列表。

注意:您可能需要添加以下依赖项才能使用DataStreamUtils:

<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-streaming-contrib</artifactId>
    <version>0.10.2</version>
</dependency>