如何为Beam管道中的会话窗口编写单元测试?

时间:2018-08-23 21:34:21

标签: google-cloud-dataflow apache-beam

我正在编写处理产品事件(创建,更新,删除)的管道。每个产品都属于具有一定持续时间的销售。我希望能够对给定销售中的所有产品进行一些汇总。出于本示例的目的,假设我只想要每笔销售的唯一商品ID列表。

因此,我的管道正在使用销售ID上的会话窗口,其间隔时间非常长(因此,当销售结束且没有更多产品更新发布时,该销售的窗口也将关闭)。我的问题是,如何为此编写单元测试?

为进行此测试,我们假设以下内容:

  • 事件只是带有销售ID和产品ID的字符串,以空格分隔,
  • applyDistinctProductsTransform基本上会执行我上面所说的内容。创建KV<String, String>元素,其中键是销售ID;设置会话窗口的间隔时间为600秒;并最终创建一个包含每次销售所有产品ID的串联字符串。

这是我到目前为止所拥有的:

我创建一个TestStream并添加一些元素:sale1的3个产品。接下来,我将水印提高到700,远远超过间隔时间。添加了另一种产品,最后将水印提高到无穷大。

@Test
public void TestSessionWindow() {
    Coder<String> utfCoder = StringUtf8Coder.of();
    TestStream<String> onTimeProducts = 
TestStream.create(utfCoder).addElements(
            TimestampedValue.of("sale1 product1", new Instant(0)),
            TimestampedValue.of("sale1 product2", new Instant(0)),
            TimestampedValue.of("sale1 product3", new Instant(0))
    )
            .advanceWatermarkTo(new Instant(700)) // watermark passes trigger time
    .addElements(
            TimestampedValue.of("campaign1 product9", new Instant(710))
    )
    .advanceWatermarkToInfinity();

    PCollection<KV<String, String>> results = applyDistinctProductsTransform(pipeline, onTimeProducts);

    PAssert.that(results).containsInAnyOrder(
            KV.of("sale1", "product1,product2,product3"),
            KV.of("sale1", "product9")
    );
    pipeline.run().waitUntilFinish();
}

但是,

  1. 管道输出的KV为sale1product1,product2,product3,product9,因此product9被附加到窗口。我希望该产品可以在单独的窗口中处理,因此最终会在输出PCollection中的不同行中出现。
  2. 如何仅在PAssert中获得单个窗口的结果?我知道有一个inWindow函数,并且找到了一个fixed time window的示例,但我不知道如何在会话窗口中执行相同的操作。

您可以查看PTransformunit test的完整代码。

1 个答案:

答案 0 :(得分:2)

1)我相信您有一个简单的单元问题。 Duration.standardSeconds以秒为单位指定了600的窗口间隔持续时间,而new Instant(long)使用毫秒,这意味着600秒的间隔大于700毫秒的时间间隔,从而导致会话合并。

2)会话仍在内部使用间隔窗口。您将需要根据触发策略计算所有会话合并后输出窗口的状态。默认情况下,会话窗口使用IntervalWindow(timestamp, gap duration),并合并所有overlapping windows以创建更大的窗口。例如,如果您为同一会话密钥设置了窗口(开始时间,结束时间),[10、14],[12、18],[4、14],则它们将全部合并为一个[4, 18]窗口。