Java 这种聚合在卡夫卡流中是如何工作的?
我是阿帕奇·卡夫卡的新手。我阅读了steam应用程序的代码,偶然发现了聚合操作。我试着自己去理解它,如果我的解释是正确的,我需要确认 下面提供了从主题和聚合中读取的代码片段Java 这种聚合在卡夫卡流中是如何工作的?,java,json,apache-kafka,apache-kafka-streams,Java,Json,Apache Kafka,Apache Kafka Streams,我是阿帕奇·卡夫卡的新手。我阅读了steam应用程序的代码,偶然发现了聚合操作。我试着自己去理解它,如果我的解释是正确的,我需要确认 下面提供了从主题和聚合中读取的代码片段 // json Serde final Serializer<JsonNode> jsonSerializer = new JsonSerializer(); final Deserializer<JsonNode> jsonDeserializer = new JsonDeserializer();
// json Serde
final Serializer<JsonNode> jsonSerializer = new JsonSerializer();
final Deserializer<JsonNode> jsonDeserializer = new JsonDeserializer();
final Serde<JsonNode> jsonSerde = Serdes.serdeFrom(jsonSerializer, jsonDeserializer);
KStreamBuilder builder = new KStreamBuilder();
// read from the topic 'bank-transactions' as `KStream`. I provided the producer below
KStream<String, JsonNode> bankTransactions = builder.stream(Serdes.String(), jsonSerde, "bank-transactions");
// we define the grouping and aggregation here
KTable<String, JsonNode> bankBalance = bankTransactions.groupByKey(Serdes.String(), jsonSerde)
.aggregate(
() -> initialBalance,
(key, transaction, balance) -> newBalance(transaction, balance),
jsonSerde,
"bank-balance-agg"
);
初始余额如下所示:
public static ProducerRecord<String, String> newRandomTransaction(String name) {
// creates an empty json {}
ObjectNode transaction = JsonNodeFactory.instance.objectNode();
Integer amount = ThreadLocalRandom.current().nextInt(0, 100);
// Instant.now() is to get the current time using Java 8
Instant now = Instant.now();
// we write the data to the json document
transaction.put("name", name);
transaction.put("amount", amount);
transaction.put("time", now.toString());
return new ProducerRecord<>("bank-transactions", name, transaction.toString());
}
// create the initial json object for balances
ObjectNode initialBalance = JsonNodeFactory.instance.objectNode();
initialBalance.put("count", 0);
initialBalance.put("balance", 0);
initialBalance.put("time", Instant.ofEpochMilli(0L).toString());
newBalance
方法获取事务和余额并返回新余额
private static JsonNode newBalance(JsonNode transaction, JsonNode balance) {
// create a new balance json object
ObjectNode newBalance = JsonNodeFactory.instance.objectNode();
newBalance.put("count", balance.get("count").asInt() + 1);
newBalance.put("balance", balance.get("balance").asInt() + transaction.get("amount").asInt());
Long balanceEpoch = Instant.parse(balance.get("time").asText()).toEpochMilli();
Long transactionEpoch = Instant.parse(transaction.get("time").asText()).toEpochMilli();
Instant newBalanceInstant = Instant.ofEpochMilli(Math.max(balanceEpoch, transactionEpoch));
newBalance.put("time", newBalanceInstant.toString());
return newBalance;
}
我有两个关于分组和聚合的问题
a。groupByKey
是否通过Serdes.String()
进行分组,而jsonSerde
是否仅对steam数据执行序列化和反序列化?Serdes.String()
是newRandomTransaction
方法中的名称字符串
b。我的断言是行的(key,transaction,balance)->newBalance(transaction,balance)
的聚合函数中的键,transaction
,从银行交易主题读取余额来自上一行的初始余额。对吗
我在调试应用程序时也感到困惑,尽管它可以无缝运行
groupByKey是否通过Serdes.String()进行分组,而jsonSerde仅对steam数据执行序列化和反序列化
是的,groupByKey是按键分组的,这些键可以作为字符串进行反序列化和比较
我的断言是行(key,transaction,balance)->newBalance(transaction,balance)的聚合函数中的key,transaction是从bank transactions主题读取的,余额来自前一行的initialBalance
差不多。初始值设定项位于第一个参数上,是的,但聚合结果将在应用程序的整个执行过程中向前推进,无休止地聚合
换句话说,您总是从初始余额
开始,然后对于每个相同的键,您将该事务
的余额添加到该键当前累计的余额
。如果您尚未看到该键被重复,则只有在该键被添加到初始余额中时才会出现
是的,您的输入主题是由KStreamsbuilder.stream
method指定的,我确信我在这里的理解很幼稚,但这是我第一次使用卡夫卡(也是流),也许举个例子会有所帮助?另外请注意,重新分区主题仅在必要时创建——对于问题中的代码段,不需要重新分区。嗨,cricket_007,我理解您的答案,并接受了它。但是,一些例子会做得更好,因为在我看来,《卡夫卡》的文档需要更好。@Matthias我将把这个例子留给你;)@如果您认为文档不足,请向AK投稿并打开PR以改进文档!