Java Apache Beam TestStream finalPane未按预期启动
我正在编写一个简单的测试来验证早期/及时/后期窗格的语义。管道组合每个键的元素数。虽然我的最后一个窗格似乎一直都是空的,但我的早期窗格和准时窗格仍按预期工作Java Apache Beam TestStream finalPane未按预期启动,java,unit-testing,testing,apache-beam,Java,Unit Testing,Testing,Apache Beam,我正在编写一个简单的测试来验证早期/及时/后期窗格的语义。管道组合每个键的元素数。虽然我的最后一个窗格似乎一直都是空的,但我的早期窗格和准时窗格仍按预期工作 private static final Duration WINDOW_LENGTH = Duration.standardMinutes(2); private static final Duration LATENESS_HORIZON = Duration.standardDays(1); 我的测试如下: @Test @Categ
private static final Duration WINDOW_LENGTH = Duration.standardMinutes(2);
private static final Duration LATENESS_HORIZON = Duration.standardDays(1);
我的测试如下:
@Test
@Category(ValidatesRunner.class)
public void simpleTest() throws Exception {
Instant baseTime = new Instant(0L);
Duration one_min = Duration.standardMinutes(1);
TestStream<KV<String, Long>> events = TestStream.create(KvCoder.of(StringUtf8Coder.of(), VarLongCoder.of()))
.advanceWatermarkTo(baseTime)
// First element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Second element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Third element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Window ends
.advanceWatermarkTo(baseTime.plus(WINDOW_LENGTH).plus(one_min))
// Late element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Fire all
.advanceWatermarkToInfinity();
PCollection<KV<String, Long>> userCount = p.apply(events).apply(new CountPipeline());
IntervalWindow window = new IntervalWindow(baseTime, WINDOW_LENGTH);
PAssert.that(userCount) // This test works
.inEarlyPane(window)
.containsInAnyOrder(
KV.of("laurens", 1L), // First firing
KV.of("laurens", 2L), // Second firing
KV.of("laurens", 3L) // Third firing
);
PAssert.that(userCount) // This test works as well
.inOnTimePane(window)
.containsInAnyOrder(
KV.of("laurens", 3L) // On time firing
);
PAssert.that(userCount) // Test fails
.inFinalPane(window)
.containsInAnyOrder(
KV.of("laurens", 4L) // Late firing
);
p.run().waitUntilFinish();
}
public static class CountPipeline extends PTransform<PCollection<KV<String, Long>>, PCollection<KV<String, Long>>> {
@Override
public PCollection<KV<String, Long>> expand(PCollection<KV<String, Long>> events) {
return events.apply("window", Window.<KV<String, Long>>into(FixedWindows.of(WINDOW_LENGTH))
.triggering(AfterWatermark
.pastEndOfWindow()
.withEarlyFirings(AfterProcessingTime
.pastFirstElementInPane())
.withLateFirings(AfterProcessingTime
.pastFirstElementInPane())
)
.withAllowedLateness(LATENESS_HORIZON)
.accumulatingFiredPanes()
.withOnTimeBehavior(Window.OnTimeBehavior.FIRE_ALWAYS)
).apply("Count", Count.perKey());
}
}
@测试
@类别(validateRunner.class)
public void simpleTest()引发异常{
Instant baseTime=新的Instant(0L);
持续时间1分钟=持续时间。标准分钟(1);
TestStream events=TestStream.create(KvCoder.of(StringUtf8Coder.of(),VarLongCoder.of()))
.advanceWatermarkTo(基准时间)
//第一个元素到达
.补遗(
TimestampedValue.of(千伏(“劳伦斯”,0L),baseTime.plus(一分钟))
)
.advanceProcessingTime(持续时间.标准分钟(5))
//第二个元素到达
.补遗(
TimestampedValue.of(千伏(“劳伦斯”,0L),baseTime.plus(一分钟))
)
.advanceProcessingTime(持续时间.标准分钟(5))
//第三要素到来了
.补遗(
TimestampedValue.of(千伏(“劳伦斯”,0L),baseTime.plus(一分钟))
)
.advanceProcessingTime(持续时间.标准分钟(5))
//窗端
.advanceWatermarkTo(baseTime.plus(窗口长度).plus(一分钟))
//迟到的人来了
.补遗(
TimestampedValue.of(千伏(“劳伦斯”,0L),baseTime.plus(一分钟))
)
.advanceProcessingTime(持续时间.标准分钟(5))
//全部解雇
.advancewatermarktofinity();
PCollection userCount=p.apply(events).apply(new CountPipeline());
IntervalWindow窗口=新的IntervalWindow(基准时间、窗口长度);
PAssert.that(userCount)//此测试有效
.inEarlyPane(窗口)
.任何订单(
千伏(“劳伦斯”,1L),//第一次开火
千伏(“劳伦斯”,2L),//第二次点火
千伏(“劳伦斯”,3L)//第三次开火
);
that(userCount)//这个测试也可以运行
.inOnTimePane(窗口)
.任何订单(
KV.of(“劳伦斯”,3L)//准时点火
);
PAssert.that(userCount)//测试失败
.inFinalPane(窗口)
.任何订单(
KV.(“劳伦斯”,4L)//延迟点火
);
p、 run().waitUntilFinish();
}
管道代号如下:
@Test
@Category(ValidatesRunner.class)
public void simpleTest() throws Exception {
Instant baseTime = new Instant(0L);
Duration one_min = Duration.standardMinutes(1);
TestStream<KV<String, Long>> events = TestStream.create(KvCoder.of(StringUtf8Coder.of(), VarLongCoder.of()))
.advanceWatermarkTo(baseTime)
// First element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Second element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Third element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Window ends
.advanceWatermarkTo(baseTime.plus(WINDOW_LENGTH).plus(one_min))
// Late element arrives
.addElements(
TimestampedValue.of(KV.of("laurens", 0L), baseTime.plus(one_min))
)
.advanceProcessingTime(Duration.standardMinutes(5))
// Fire all
.advanceWatermarkToInfinity();
PCollection<KV<String, Long>> userCount = p.apply(events).apply(new CountPipeline());
IntervalWindow window = new IntervalWindow(baseTime, WINDOW_LENGTH);
PAssert.that(userCount) // This test works
.inEarlyPane(window)
.containsInAnyOrder(
KV.of("laurens", 1L), // First firing
KV.of("laurens", 2L), // Second firing
KV.of("laurens", 3L) // Third firing
);
PAssert.that(userCount) // This test works as well
.inOnTimePane(window)
.containsInAnyOrder(
KV.of("laurens", 3L) // On time firing
);
PAssert.that(userCount) // Test fails
.inFinalPane(window)
.containsInAnyOrder(
KV.of("laurens", 4L) // Late firing
);
p.run().waitUntilFinish();
}
public static class CountPipeline extends PTransform<PCollection<KV<String, Long>>, PCollection<KV<String, Long>>> {
@Override
public PCollection<KV<String, Long>> expand(PCollection<KV<String, Long>> events) {
return events.apply("window", Window.<KV<String, Long>>into(FixedWindows.of(WINDOW_LENGTH))
.triggering(AfterWatermark
.pastEndOfWindow()
.withEarlyFirings(AfterProcessingTime
.pastFirstElementInPane())
.withLateFirings(AfterProcessingTime
.pastFirstElementInPane())
)
.withAllowedLateness(LATENESS_HORIZON)
.accumulatingFiredPanes()
.withOnTimeBehavior(Window.OnTimeBehavior.FIRE_ALWAYS)
).apply("Count", Count.perKey());
}
}
公共静态类CountPipeline扩展了pttransform{
@凌驾
公共PCollection扩展(PCollection事件){
return events.apply(“window”,window.into(FixedWindows.of(window_长度))
.触发(后水印)
.pastEndOfWindow()
.使用早期点火(处理时间后
.pastFirstElementInPane())
.延迟点火(处理时间后
.pastFirstElementInPane())
)
.允许迟到(迟到/地平线)
.累积燃烧烷()
.withOnTimeBehavior(Window.OnTimeBehavior.FIRE\u始终)
).apply(“Count”,Count.perKey());
}
}
错误:
Expected: iterable over [<KV{laurens, 4}>] in any order
but: No item matches: <KV{laurens, 4}> in []
应为:可按任意顺序在[]上计算
但是:没有与[]中的匹配项
正如您所看到的,最后一个元素肯定是在水印之后被摄取的,根据定义,这应该会使它延迟。不过,最后一个窗格不包含原始结果的细化。老实说,我不知道为什么晚窗格没有被释放。非常感谢您的见解。FinalPane与LatePane不同 在您的测试中,FinalPane应该是空的,因为您的测试用例为每个元素触发触发器,所以FinalPane中不会留下任何人
正如我从评论中读到的那样,您的意图是正确的,即针对LatePane进行测试。由于未知原因,PAssert util函数列表中缺少LatePane的这种特殊情况。我做了一个PR来解决这个问题:FinalPane与LatePane不同 在您的测试中,FinalPane应该是空的,因为您的测试用例为每个元素触发触发器,所以FinalPane中不会留下任何人
正如我从评论中读到的那样,您的意图是正确的,即针对LatePane进行测试。由于未知原因,PAssert util函数列表中缺少LatePane的这种特殊情况。我做了一个公关来解决这个问题:非常有意义。我已经在想为什么它被命名为finalPane而不是latePane。我真丢脸。谢谢你的澄清!这很有道理。我已经在想为什么它被命名为finalPane而不是latePane。我真丢脸。谢谢你的澄清!