Beam - 会话窗口未按预期排放结果

时间:2017-10-06 13:04:22

标签: java google-cloud-dataflow apache-beam

我正在构建一个Apache Beam(v2.0)管道,以便在Google Cloud Dataflow中运行。预期的流程是:

  • 来自Pub / Sub的事件流(无界数据源)。它们是简单的JSON对象,具有sessionId属性。
  • 将事件的自定义DoFn用于KV<String, String>,其中键为sessionId,值为整个JSON对象。
  • 使用会话窗口的窗口事件(开发时间间隔为2秒,生产时间约为30分钟)。
  • 目前,只需打印从每个窗口发出的结果

以下是管道代码:

   Pipeline pipeline = Pipeline.create(options);

    pipeline.apply(PubsubIO
                    .readStrings()
                    .fromSubscription(options.getSubscription()))

        .apply("AddKeyFn", ParDo.of(new DoFn<String, KV<String, String>>() {
            @ProcessElement
            public void processElement(ProcessContext c) {
                Gson gson = new Gson();
                String key = (String) gson.fromJson(c.element(), HashMap.class).get("sessionId");
                KV<String, String> kv = KV.of(key, c.element());
                c.output(kv);
            }
          }))


        .apply(Window.<KV<String, String>>into(Sessions.withGapDuration(Duration.standardSeconds(2))))

        .apply("PrintFn", ParDo.of(new DoFn<KV<String, String>, Void>() {
            @ProcessElement
            public void processElement(ProcessContext c) {
                System.out.println("****");
                System.out.println(c.element());
                System.out.println(c.timestamp());
            }
          }));

        return pipeline.run();

我希望Window函数在每次会话结束时为每个会话(基于密钥)发出结果。出于测试目的,我使用pub / sub仿真器,只是随机发送数据。

因此,例如,如果将以下数据发送到pub / sub:

{"sessionId": "2", "data": "data9583", "timestamp": 1507293681}
{"sessionId": "3", "data": "data5220", "timestamp": 1507293683}
{"sessionId": "6", "data": "data2998", "timestamp": 1507293684}
{"sessionId": "3", "data": "data3820", "timestamp": 1507293684}
{"sessionId": "6", "data": "data5728", "timestamp": 1507293685}
{"sessionId": "6", "data": "data7173", "timestamp": 1507293686}
{"sessionId": "4", "data": "data8800", "timestamp": 1507293687}

Window函数应发出以下内容:

  • 第一个窗口:包含sessionId=2
  • 的事件
  • 第二个窗口:包含2个sessionId=3
  • 的事件
  • 第3个窗口:包含3个sessionId=6
  • 的事件
  • 第4个窗口:包含1个sessionId=4
  • 的事件

这里的想法是:

  • Windows只会在会话结束后才会发出&#34;完成&#34;,也就是说自上次使用该sessionId事件后已经过{gapDuration}
  • 每个窗口将包含来自单个会话的事件(因为我们已将KV<String, String>传递到Window函数中)

上面的窗口函数直接来自Beam documentation

我实际看到的是:

  • 点击pub / sub后立即打印每个事件,因此管道甚至不等{gapDuration}发出窗口
  • 每个print语句都包含一个事件

值得注意的是,如果我添加一个自定义CombineFn(它只是将JSON对象转换为一个JSON对象数组),那么CombineFn 都没有。到PrintFn(我在CombineFn中添加了一个打印声明。)

我假设触发与此有关,但似乎找不到任何有用的东西让我朝着正确的方向(有一些令人惊讶的少量示例代码用于Beam,特别是2.0。

我的问题:

  • 我想要的行为可能吗?
  • 如果是这样,我错过了什么?这种方法至少是在正确的轨道上吗?
  • 如果有人能指出我为各种Beam管道用例提供示例代码的良好来源,那就太棒了!

资源我一直没有成功:

1 个答案:

答案 0 :(得分:3)

首先,需要在窗口之间合并元素的窗口函数需要应用聚合操作,例如GroupByKey或Combine。这在Windowing Basics下的Beam编程指南中进行了讨论。

其次,PubSub默认情况下(正如您所使用的)将根据元素的发布时间为元素分配时间戳。由于您有明确的时间戳字段,因此您可能希望查看使用时间戳属性发布这些元素,并使用withTimestampAttribute method读取它们。这将使用您发布的timestamp属性作为时间戳。