作为我们的应用程序逻辑的一部分,我们使用Kafka Streams状态存储进行范围查找,使用builder.table()
方法从Kafka主题加载数据。
问题是源主题的密钥被序列化为JSON,并且不适合基于RocksDB的状态存储内部使用的二进制密钥比较。
我们希望通过将密钥传递给Materialized.as()
来使用单独的serde。但是,看起来流实现重置传递给用于从表主题加载的原始serdes的任何内容。
这是我在流构建器内部可以看到的内容:
public synchronized <K, V> KTable<K, V> table(final String topic,
final Consumed<K, V> cons,
final Materialized<K, V, KeyValueStore<Bytes, byte[]>> materialized) {
Objects.requireNonNull(topic, "topic can't be null");
Objects.requireNonNull(consumed, "consumed can't be null");
Objects.requireNonNull(materialized, "materialized can't be null");
materialized.withKeySerde(consumed.keySerde).withValueSerde(consumed.valueSerde);
return internalStreamsBuilder.table(topic,
new ConsumedInternal<>(consumed),
new MaterializedInternal<>(materialized, internalStreamsBuilder, topic + "-"));
}
任何人都知道为什么这样做,以及是否可以为DSL状态商店使用不同的serde? p>
请不要建议使用Processor API,这条路线已经过充分探索。每次我需要在将数据保存到状态存储之前按摩数据时,我想避免编写处理器和自定义状态存储。
经过一些挖掘流源后,我发现我可以使用始终为真的谓词将自定义Materialized.as
传递给过滤器。但它闻起来有点黑客。
这是我的代码,遗憾的是,我们没有按照我们希望的方式工作,因为&#34; serdes reset&#34;如上所述。
Serde<Value> valueSerde = new JSONValueSerde()
KTable<Key, Value> table = builder.table(
tableTopic,
Consumed.with(new JSONKeySerde(), valueSerde)
Materialized.as(cacheStoreName)
.withKeySerde(new BinaryComparisonsCompatibleKeySerde())
.withValueSerde(valueSerde)
)
答案 0 :(得分:0)
代码按设计工作。从流的角度来看,没有理由为商店使用不同的Serde来读取主题中的数据,因为它知道是相同的数据。因此,如果一个人不使用StreamsConfig中的默认Serdes,那么只需指定一次Serde(Consumed
),并且不需要在Materialized
中指定它试。
对于您的特殊情况,您可以将该主题作为流来阅读&#34;虚拟聚合&#34;只返回每条记录的最新值(而不是计算实际的聚合)。这允许您为结果类型指定不同的Serde。