从自定义源写入数据以连续方式进行flink

时间:2017-07-31 06:48:37

标签: java apache-flink flink-streaming flink-cep

这是我第一次使用Apache Flink(1.3.1)并提出问题。更详细地说,我正在使用flink-core,flink-cep和flink-streaming库。我的应用程序是一个Akka ActorSystem,它消耗来自RabbitMQ的消息,各种各样的actor处理这些消息。在某些actor中,我想从Flink实例化StreamExecutionEnvironment并处理传入的消息。因此,我编写了一个自定义源类,扩展了RichSourceFunction类。一切正常,除了一件事:我不知道如何将数据发送到我的Flink扩展。这是我的设置:

public class FlinkExtension {

    private static StreamExecutionEnvironment environment;
    private DataStream<ValueEvent> input;
    private CustomSourceFunction function;

    public FlinkExtension(){

        environment = StreamExecutionEnvironment.getExecutionEnvironment();

        function = new CustomSourceFunction();
        input = environment.addSource(function);

        PatternStream<ValueEvent> patternStream = CEP.pattern(input, _pattern());

        DataStream<String> warnings = patternStream.select(new PatternSelectFunction<ValueEvent, String>() {
            @Override
            public String select(Map<String, List<ValueEvent>> pattern) throws Exception {
                return null; //TODO
            }
        });

        warnings.print();

        try {
            environment.execute();
        } catch(Exception e){
            e.printStackTrace();
        }

    }

    private Pattern<ValueEvent, ?> _pattern(){

        return Pattern.<ValueEvent>begin("first").where(new SimpleCondition<ValueEvent>() {
            @Override
            public boolean filter(ValueEvent value) throws Exception {
                return value.getValue() > 10;
            }
        });
    }

    public void sendData(ValueEvent value){
        function.sendData(value);
    }
}

这是我的自定义源函数:

public class CustomSourceFunction extends RichSourceFunction<ValueEvent> {

    private volatile boolean run = false;
    private SourceContext<ValueEvent> context;

    @Override
    public void open(Configuration parameters){
        run = true;
    }

    @Override
    public void run(SourceContext<ValueEvent> ctx) throws Exception {
        this.context = ctx;

        while (run){

        }
    }

    public void sendData(ValueEvent value){
        this.context.collectWithTimestamp(value, Calendar.getInstance().getTimeInMillis());
    }

    @Override
    public void cancel() {
        run = false;
    }
}

所以我想从外部调用sendData类中的方法FlinkExtension,以连续的方式将数据写入FlinkExtension。这是我的JUnit测试应该将数据发送到扩展,然后将数据写入SourceContext

@Test
public void testSendData(){
    FlinkExtension extension = new FlinkExtension();
    extension.sendData(new ValueEvent(30));
}

但是如果我运行测试,没有任何反应,应用程序会挂起CustomSourceFunction的run方法。我还尝试在CustomSourceFunction run方法中创建一个新的无限线程。

总结一下:有人知道如何以连续的方式将数据从应用程序写入Flink实例吗?

2 个答案:

答案 0 :(得分:2)

Flink源连接器通过让run()方法在while(run)循环内调用collect()(或collectWithTimestamp())来发出连续的数据流。如果你想研究一个例子,Apache NiFi源并不像大多数人那么复杂; here's its run method

答案 1 :(得分:0)

问题是CustomSourceFunction方法和run方法使用sendData的不同对象实例。因此,context对象不会在方法之间共享,并且添加新的ValueEvent是行不通的。

要解决此问题,请将run方法使用的对象实例存储为CustomSourceFunction类的静态成员变量。当您需要创建新的ValueEvent时,请在同一对象实例上调用sendData方法。

请参见下面的示例代码

package RuleSources;

import Rules.Rule;
import org.apache.flink.streaming.api.watermark.Watermark;

import java.util.ArrayList;

public class DynamicRuleSource extends AlertingRuleSource {
    private static DynamicRuleSource sourceObj;

    private SourceContext<Rule> ctx;

    public static DynamicRuleSource getSourceObject() {
        return sourceObj;
    }

    public void run(SourceContext<Rule> ctx) throws Exception {
        this.ctx = ctx;
        sourceObj = this;
        while(true) {
            Thread.sleep(100);
        }
    }

    public void addRule(Rule rule) {
        ctx.collect(rule);
    }

    @Override
    public void cancel() {
    }
}

添加新规则

 public static void addRule(Rule rule) throws Exception {
        AlertingRuleSource sourceObject = DynamicRuleSource.getSourceObject();
        sourceObject.addRule(rule);
    }