由于Windows的存在,处理流事件并在每小时的存储桶中写入文件是一个挑战,因为传入小时中的某些事件可能会进入以前的事件中。
我一直在研究Apache Beam及其触发器,但是我正在努力按如下方式使用时间戳来管理触发器...
Window.<GenericRecord>into(FixedWindows.of(Duration.standardMinutes(1)))
.triggering(AfterProcessingTime
.pastFirstElementInPane()
.plusDelayOf(Duration.standardSeconds(1)))
.withAllowedLateness(Duration.ZERO)
.discardingFiredPanes())
到目前为止,这是我一直在做的事情,无论时间戳是什么,都会触发1分钟的窗口。但是,我想将时间戳记包含在对象中,以便仅针对其中的对象触发时间戳记。
Window.<GenericRecord>into(FixedWindows.of(Duration.standardMinutes(1)))
.triggering(AfterWatermark
.pastEndOfWindow())
.withAllowedLateness(Duration.ZERO)
.discardingFiredPanes())
我要处理的对象具有时间戳记对象,但是,这是一个长字段,而不是Instant
字段。
"{ \"name\": \"timestamp\", \"type\": \"long\", \"logicalType\": \"timestamp-micros\" },"
让我的POJO类具有long
字段不会触发任何操作,但是如果我将其交换为Instant
类并正确地重新创建对象,则每当读取PubSub消息时都会引发以下错误。 / p>
Caused by: java.lang.ClassCastException: org.apache.avro.generic.GenericData$Record cannot be cast to java.lang.Long
我也一直在考虑围绕GenericRecord创建一种包装类,其中包含一个时间戳,但是一旦准备好将FileIO写入.parquet,就需要在其中使用GenericRecord部分。
我还必须使用其他哪些方式使用水印触发器?
编辑:@Anton评论之后,我尝试了以下方法。
.apply("Apply timestamps", WithTimestamps.of(
(SerializableFunction<GenericRecord, Instant>) item -> new Instant(Long.valueOf(item.get("timestamp").toString())))
.withAllowedTimestampSkew(Duration.standardSeconds(30)))
即使它已被弃用,但它似乎已通过管道,但仍未写入(由于先前显示的触发器,由于某种原因仍在被丢弃之前写入?)。
还使用outputWithTimestamp
尝试了另一种提到的方法,但是由于延迟,它打印出以下错误...
Caused by: java.lang.IllegalArgumentException: Cannot output with timestamp 2019-06-12T18:59:58.609Z. Output timestamps must be no earlier than the timestamp of the current input (2019-06-12T18:59:59.848Z) minus the allowed skew (0 milliseconds). See the DoFn#getAllowedTimestampSkew() Javadoc for details on changing the allowed skew.