自从我使用Json值以来,我还没有设置默认的Serdes。
我处理KStream,并使用必需的spring和product(json)serdes来使用它,但下一步(映射操作)失败:
val props = Properties()
props[StreamsConfig.APPLICATION_ID_CONFIG] = applicationName
props[StreamsConfig.BOOTSTRAP_SERVERS_CONFIG] = kafkaBootstrapServers
val productSerde: Serde<Product> = Serdes.serdeFrom(JsonPojoSerializer<Product>(), JsonPojoDeserializer(Product::class.java))
builder.stream(INVENTORY_TOPIC, Consumed.with(Serdes.String(), productSerde))
.map { key, value ->
KeyValue(key, XXX)
}
.aggregate(...)
如果我删除了地图操作,执行就可以了。
我还没有找到一种方法来指定map()的Serdes,怎么做?
错误:
Caused by: org.apache.kafka.streams.errors.StreamsException: A serializer (key: org.apache.kafka.common.serialization.ByteArraySerializer / value: org.apache.kafka.common.serialization.ByteArraySerializer) is not compatible to the actual key or value type (key type: java.lang.String / value type: com.codependent.kafkastreams.inventory.dto.Product). Change the default Serdes in StreamConfig or provide correct Serdes via method parameters.
at org.apache.kafka.streams.processor.internals.SinkNode.process(SinkNode.java:92)
答案 0 :(得分:0)
多个问题:
致电map()
后,您致电groupByKey().aggregate()
。这将触发数据重新分区,因此在将map()
数据写入内部主题以进行数据重新分区之后。因此,您还需要在Serde
中提供相应的groupByKey()
。
但是,因为您没有修改密钥,所以实际上应该调用mapValues()
,以避免不必要的重新分区。
请注意,您需要为每个不应使用配置中默认Serde
的运算符提供Serde
。 Serde
不沿下游传递,而是操作员就地覆盖。 (Kafka 2.1正在进行改进。)
答案 1 :(得分:0)
如果有人像我一样来到这里,这里有一个演示 Matthias 解决方案的实际示例。由于 ClassCastException,以下代码将失败。
builder.stream(
"my-topic",
Consumed.with(Serdes.String(), customSerde))
.map((k, v) -> {
// You've modified the key. Get ready for an error!
String newKey = k.split(":")[0];
return KeyValue.pair(newKey.toString(), v);
})
.groupByKey()
.aggregate(
MyAggregate::new,
(key, data, aggregation) -> {
// You'll never reach this block due to an error similar to:
// ClassCastException while producing data to topic
return aggregation.updateFrom(shot);
},
Materialized.<String, MyAggregate> as(storeSupplier)
.withKeySerde(Serdes.String())
.withValueSerde(aggregateSerde)
)
正如 Matthias 所提到的,“您需要在 groupByKey 中提供相应的 Serdes”。方法如下:
builder.stream(
"my-topic",
Consumed.with(Serdes.String(), customSerde))
.map((k, v) -> {
// You've modified the key. Get ready for an error!
String newKey = k.split(":")[0];
return KeyValue.pair(newKey.toString(), v);
})
// Voila, you've specified the serdes required by the new internal
// repartition topic and you can carry on with your work
.groupByKey(Grouped.with(Serdes.String(), customSerde))
.aggregate(
MyAggregate::new,
(key, data, aggregation) -> {
// You'll never reach this block due to an error similar to:
// ClassCastException while producing data to topic
return aggregation.updateFrom(shot);
},
Materialized.<String, MyAggregate> as(storeSupplier)
.withKeySerde(Serdes.String())
.withValueSerde(aggregateSerde)
)