Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Kafka streams处理批处理数据以重置聚合_Java_Apache Kafka_Apache Kafka Streams - Fatal编程技术网

Java Kafka streams处理批处理数据以重置聚合

Java Kafka streams处理批处理数据以重置聚合,java,apache-kafka,apache-kafka-streams,Java,Apache Kafka,Apache Kafka Streams,我的卡夫卡主题“datasource”中有一些数据,其模式如下(此处为演示简化): 这些数据来自批量运行,我们接受所有交易并重新计算其价值。将其视为一天的开始过程——此时,这里是所有位置的一组新数据。当init和commit消息没有发送到真正的主题时,它们会被生产者过滤掉 白天,随着情况的变化,会有更新。这将提供新数据(在本例中,我们可以忽略覆盖数据,因为这将通过重新运行批处理来处理): 该数据以KStream“positions”的形式进入应用程序 另一个主题“位置”列出了可能的位置。它们作

我的卡夫卡主题“datasource”中有一些数据,其模式如下(此处为演示简化):

这些数据来自批量运行,我们接受所有交易并重新计算其价值。将其视为一天的开始过程——此时,这里是所有位置的一组新数据。当init和commit消息没有发送到真正的主题时,它们会被生产者过滤掉

白天,随着情况的变化,会有更新。这将提供新数据(在本例中,我们可以忽略覆盖数据,因为这将通过重新运行批处理来处理):

该数据以KStream“positions”的形式进入应用程序


另一个主题“位置”列出了可能的位置。它们作为一个可扩展的位置拉入java kafka streams应用程序:

{ "id": 1, "name": "Mars" },
{ "id": 2, "name": "Earth"}

计划是使用java 9 kafka streams应用程序来聚合这些值,并按位置分组。输出应该类似于:

{ "id": 1, "location": "Earth", "sum": 250.0 },
{ "id": 2, "location": "Mars": "sum": 200.0 }
这是我迄今为止的工作:

StreamsBuilder builder = new StreamsBuilder();

/** snip creating serdes, settings up stores, boilerplate  **/

final GlobalKTable<Integer, Location> locations = builder.globalTable(
                LOCATIONS_TOPIC, 
                /* serdes, materialized, etc */
                );

final KStream<Integer, PositionValue> positions = builder.stream(
                POSITIONS_TOPIC,
                /* serdes, materialized, etc */
            );

/* The real thing is more than just a name, so a transformer is used to match locations to position values, and filter ones that we don't care about */
KStream<Location, PositionValue> joined = positions
                .transform(() -> new LocationTransformer(), POSITION_STORE) 
                .peek((location, positionValue) -> { 
                    LOG.debugv("Processed position {0} against location {1}", positionValue, location);
                });

/** This is where it is grouped and aggregated here **/
joined.groupByKey(Grouped.with(locationSerde, positionValueSerde))
            .aggregate(Aggregation::new, /* initializer */
                       (location, positionValue, aggregation) -> aggregation.updateFrom(location, positionValue), /* adder */
                Materialized.<Location, Aggregation>as(aggrStoreSupplier)
                    .withKeySerde(locationSerde)
                    .withValueSerde(aggregationSerde)
            );

Topology topo = builder.build();
StreamsBuilder builder=newstreamsbuilder();
/**剪断创建序列、设置商店、样板文件**/
最终GlobalKTable位置=builder.globalTable(
主题的位置,
/*塞德斯、物化等*/
);
最终KStream位置=builder.stream(
关于这一主题的立场,
/*塞德斯、物化等*/
);
/*真正的东西不仅仅是一个名字,所以一个转换器被用来匹配位置和位置值,并过滤我们不关心的值*/
KStream=位置
.transform(()->新位置Transformer(),位置存储)
.peek((位置、位置值)->{
debugv(“针对位置{1}处理的位置{0}”,位置值,位置);
});
/**这是它在这里分组和聚合的地方**/
joined.groupByKey(分组为(locationSerde,positionValueSerde))
.aggregate(聚合::新,/*初始值设定项*/
(位置,位置值,聚合)->aggregation.updateFrom(位置,位置值),/*加法器*/
物化.as(aggrStoreSupplier)
.带钥匙塞(位置SERDE)
.withValueSerde(聚合服务器)
);
拓扑拓扑拓扑=builder.build();
我遇到的问题是,这是对所有内容的聚合,因此每天的批处理,加上更新,然后是下一个每天的批处理,都会被添加。基本上,我需要一种方式来表示“这是下一组批处理数据,根据此重置”。我不知道怎么做-请帮帮我


谢谢

如果我理解正确,您希望聚合数据,但只聚合最后一天的数据,并丢弃其余数据

我建议您聚合到一个中间类中,该类包含流中的所有值,并且还具有过滤其他日期数据的逻辑。如果我理解正确,那将丢弃“batch”类型最后一个数据之前的所有数据


虽然在Kotlin,我做了一个可以在需要时查看的示例。

您可以做一些事情,但我建议使用时间窗口流。您可以将时间设置为1天的滚动窗口,并在该流上执行搜索。最终,您将在KTable中的自己窗口中聚合每天。这样,您就不必担心丢弃数据(尽管您可以这样做),每天都将被分隔开


这里有几个很好的例子说明它们是如何工作的:

我考虑过这一点,但一天并不总是在同一时间点。所以今天它可能会在凌晨2点,明天凌晨2点05分重置,等等。我认为重叠可能会导致问题。有编程窗口这样的东西吗?也有会话窗口,它们根据两个记录之间的时间间隔对记录进行分组。如果数据是成批提供的,那么在2.7版中可能会对您起作用,同时还会有滑动窗口,在每个窗口中保持相同数量的记录。尽管我不认为这也能满足你的需要,但你确实理解正确。谢谢,我会看看这个,看看是否适合我的需要。我仍然习惯于流和拓扑。我的示例中的代码将计算主题上有多少个STARTED类型的ProcessingEvents,但它将丢弃任何FINISHED类型的ProcessingEvents。它将数据收集到一个名为ProcessingEventDto的中间类中,该类具有确定ProcessingEvent是否完成的逻辑,并负责提供启动次数的计数谢谢-我最后标记了一个位置以指示何时需要重置,并在聚合器中使用该位置:“如果”(measurement.dealNum==PositionValue.RESET_标志)返回null;否则返回aggregate.updateFrom(limit,measurement)```
{ "id": 1, "location": "Earth", "sum": 250.0 },
{ "id": 2, "location": "Mars": "sum": 200.0 }
StreamsBuilder builder = new StreamsBuilder();

/** snip creating serdes, settings up stores, boilerplate  **/

final GlobalKTable<Integer, Location> locations = builder.globalTable(
                LOCATIONS_TOPIC, 
                /* serdes, materialized, etc */
                );

final KStream<Integer, PositionValue> positions = builder.stream(
                POSITIONS_TOPIC,
                /* serdes, materialized, etc */
            );

/* The real thing is more than just a name, so a transformer is used to match locations to position values, and filter ones that we don't care about */
KStream<Location, PositionValue> joined = positions
                .transform(() -> new LocationTransformer(), POSITION_STORE) 
                .peek((location, positionValue) -> { 
                    LOG.debugv("Processed position {0} against location {1}", positionValue, location);
                });

/** This is where it is grouped and aggregated here **/
joined.groupByKey(Grouped.with(locationSerde, positionValueSerde))
            .aggregate(Aggregation::new, /* initializer */
                       (location, positionValue, aggregation) -> aggregation.updateFrom(location, positionValue), /* adder */
                Materialized.<Location, Aggregation>as(aggrStoreSupplier)
                    .withKeySerde(locationSerde)
                    .withValueSerde(aggregationSerde)
            );

Topology topo = builder.build();