我的问题是关于 Kafka 流 Ktable.groupBy.aggregate。以及由此产生的聚合值。
情况
我正在尝试每天汇总分钟事件。
我有一个分钟事件生成器(此处未显示),可为一些房屋生成事件。有时事件值错误,必须重新发布分钟事件。 分钟事件发布在“分钟”主题中。
我正在使用kafka StreamsgroupBy
和aggregate
.
问题
通常,由于一天有 1440 分钟,因此不应有超过 1440 个值的聚合。此外,永远不应该有一个包含负数事件的聚合。
...但无论如何它都会发生,我们不明白我们的代码有什么问题。
示例代码
这是一个示例简化代码来说明问题。有时会抛出 IllegalStateException。
StreamsBuilder builder = new StreamsBuilder();
KTable<String, MinuteEvent> minuteEvents = builder.table(
"minutes",
Consumed.with(Serdes.String(), minuteEventSerdes),
Materialized.<String, MinuteEvent, KeyValueStore<Bytes, byte[]>>with(Serdes.String(), minuteEventSerdes)
.withCachingDisabled());
// preform daily aggregation
KStream<String, MinuteAggregate> dayEvents = minuteEvents
// group by house and day
.filter((key, minuteEvent) -> minuteEvent != null && StringUtils.isNotBlank(minuteEvent.house))
.groupBy((key, minuteEvent) -> KeyValue.pair(
minuteEvent.house + "##" + minuteEvent.instant.atZone(ZoneId.of("Europe/Paris")).truncatedTo(ChronoUnit.DAYS), minuteEvent),
Grouped.<String, MinuteEvent>as("minuteEventsPerHouse")
.withKeySerde(Serdes.String())
.withValueSerde(minuteEventSerdes))
.aggregate(
MinuteAggregate::new,
(String key, MinuteEvent value, MinuteAggregate aggregate) -> aggregate.addLine(key, value),
(String key, MinuteEvent value, MinuteAggregate aggregate) -> aggregate.removeLine(key, value),
Materialized
.<String, MinuteAggregate, KeyValueStore<Bytes, byte[]>>as(BILLLINEMINUTEAGG_STORE)
.withKeySerde(Serdes.String())
.withValueSerde(minuteAggSerdes)
.withLoggingEnabled(new HashMap<>())) // keep this aggregate state forever
.toStream();
// check daily aggregation
dayEvents.filter((key, value) -> {
if (value.nbValues < 0) {
throw new IllegalStateException("got an aggregate with a negative number of values " + value.nbValues);
}
if (value.nbValues > 1440) {
throw new IllegalStateException("got an aggregate with too many values " + value.nbValues);
}
return true;
}).to("days", minuteAggSerdes);
以下是此代码片段中使用的示例类:
public class MinuteEvent {
public final String house;
public final double sensorValue;
public final Instant instant;
public MinuteEvent(String house,double sensorValue, Instant instant) {
this.house = house;
this.sensorValue = sensorValue;
this.instant = instant;
}
}
public class MinuteAggregate {
public int nbValues = 0;
public double totalSensorValue = 0.;
public String house = "";
public MinuteAggregate addLine(String key, MinuteEvent value) {
this.nbValues = this.nbValues + 1;
this.totalSensorValue = this.totalSensorValue + value.sensorValue;
this.house = value.house;
return this;
}
public MinuteAggregate removeLine(String key, MinuteEvent value) {
this.nbValues = this.nbValues -1;
this.totalSensorValue = this.totalSensorValue - value.sensorValue;
return this;
}
public MinuteAggregate() {
}
}
如果有人能告诉我们我们在这里做错了什么以及为什么我们有这些意想不到的价值,那就太好了。
补充说明
- 我们将流作业配置为使用 4 个线程运行
properties.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, 4);
- 我们被迫使用 a ,因为对于已发布的 Instant,可以使用不同的
Ktable.groupBy().aggregate()
分钟值 重新发布。sensorValue
并且每日聚合相应地修改。Stream.groupBy().aggregate()
没有adder
ANDsubstractor
。