Apache Flink:自定义触发器的行为异常

时间:2018-12-12 15:58:40

标签: java apache-flink flink-streaming

我有一个由事件组成的DataStream,该事件的属性表示一批生产的元素。在我从同一生产批次中提取的每个事件中,该属性(称为“ batchNumber”)都是恒定的。每批我收到多个事件。

当“ batchNumber”更改时,我想分析一批中的机器性能。我的方法是使用全局流,并使用“ batchNumber”作为键对其进行分区。我希望这会将全局流划分为多个窗口,其中每个事件都带有“ batchNumber”。然后定义一个触发器,当“ batchNumber”更改时应触发。然后,我可以在ProcessWindowFunction中分析聚合的数据。

我的问题是:

  • 当产品更改时,触发器并不总是触发
  • 即使触发,也仅聚合了一个元素。我预计将接近200。

这是我正在使用的代码。

    public class batchnrTrigger extends Trigger<ImaginePaperData, GlobalWindow> {

    private static final long serialVersionUID = 1L;

    public batchnrTrigger() {}

    private final ValueStateDescriptor<Integer> prevbatchnr = new ValueStateDescriptor<>("batchnr", Integer.class);

    @Override
    public TriggerResult onElement(ImaginePaperData element, long timestamp, GlobalWindow window, TriggerContext ctx) throws Exception {

        ValueState<Integer> batchnrState = ctx.getPartitionedState(prevbatchnr);

        if (batchnrState == null || batchnrState.value() == null || !(element.batchnr == batchnrState.value())) {

            System.out.println("batchnr BEFORE: " + batchnrState.value() + "   NEW batchnr: " + element.batchnr + " ==> should fire and process elements from window!");
            batchnrState.update(element.batchnr);
            return TriggerResult.FIRE;

        }

        System.out.println("batchnr BEFORE: " + batchnrState.value() + "   NEW batchnr: " + element.batchnr + " ==> should not fire and continue ingesting elements!");
        batchnrState.update(element.batchnr);
        return TriggerResult.CONTINUE;
    }

    @Override
    public TriggerResult onProcessingTime(long time, GlobalWindow window, TriggerContext ctx) throws Exception {
        return TriggerResult.CONTINUE;
    }

    @Override
    public TriggerResult onEventTime(long time, GlobalWindow window, TriggerContext ctx) throws Exception {
        return TriggerResult.CONTINUE;
    }

    @Override
    public void clear(GlobalWindow window, TriggerContext ctx) throws Exception {

    }

}

这就是我所说的触发器:

DataStream<String> imaginePaperDataStream = nifiStreamSource
        .map(new ImaginePaperDataConverter())
        .keyBy((ImaginePaperData event) -> event.lunum)
        .window(GlobalWindows.create())
        .trigger(new LunumTrigger())
        .process(new ImaginePaperWindowReportFunction());

我知道这个问题类似于this问题。但是我正在使用ValueState,我认为我的解雇条件根本不相似。

我该如何工作?

1 个答案:

答案 0 :(得分:1)

您确定要通过event.lunum来键入流吗?如果您预期lunum的每个不同值大约有200个事件,则这是有道理的。但是,如果每个批次的lunum值中只有一个事件,那将解释您看到的行为。

您还确定自己的事件正在按顺序处理吗?如果批处理是通过并行进程之间的竞争条件在处理管道中的某个位置交错的,那么这也可能有助于解释您所看到的内容。

此外,您应该使用触发器的clear方法清除状态。并且您将需要实现一个Evictor,以便在处理完窗口后从窗口中删除元素。

窗口API的这一部分非常复杂。我认为这个特定的应用程序将更直接地实现为RichFlatMap,该RichFlatMap可以在ListState中收集项目,直到批号更改(您将其保留在ValueState中)为止。