我有一个拓扑,其中有一个流A
。
从该流A
,创建一个WindowedStore S
。
A --> [S]
然后我想根据S
上的数据对A中的对象进行转换,并使这些转换后的对象(通过transformValues
到达WindowStore逻辑。
为此,我为此创建了一个Transformer,创建了一个流A'
,并使窗口知道它(即,S
将由A'
而不是来自A
)。
A -> A' --> [S]
^__read__|
但是我不能这样做,因为创建拓扑时会引发异常:
Caused by: org.apache.kafka.streams.errors.TopologyException: Invalid topology: StateStore storeName is not added yet.
有没有办法解决这个问题?这是一个限制吗?
代码示例:
// A
val sessionElementsStream: KStream[K, SessionElement] = ...
// A'
val sessionElementsTransformed : KStream[K, SessionElementTransformed] = {
// Here we use the sessionStoreName - but it is not added yet to the Topology
sessionElementsStream.
transformValues(sessionElementTransformerSupplier, sessionStoreName)
}
val sessionElementsWindowedStream: SessionWindowedKStream[K, SessionElementTransformed] = {
sessionElementsTransformed.
groupByKey(sessionElementTransformedGroupedBy).
windowedBy(sessionWindows)
}
val sessionStore : KTable[Windowed[K], List[WindowedSession]] =
sessionElementsWindowedStream.aggregate(
initializer = List.empty[WindowedSession])(
aggregator = anAggregator, merger = aMerger)(materialized = getMaterializedMUPKSessionStore(sessionStoreName))
最初的问题是,根据之前会话的值,我想在此之后更改会话。但是,如果我在会话后 之后在转换器中执行此操作,则可以更改这些转换后的会话并将其发送到下游-但它们不会在S
中反映出它们的新状态-因此,对存储区将保留旧值。
Kafka Streams 2.1,Scala 2.12.4。 共同划分的主题。
更新
有一种方法可以在DSL中使用一个额外的主题:
to
个主题builder.stream
并从中建立商店。但是,在这里不得不使用额外的主题听起来很麻烦。没有其他更简单的解决方法了吗?
答案 0 :(得分:0)
但是我不能这样做,因为创建拓扑时会引发异常:
Caused by: org.apache.kafka.streams.errors.TopologyException: Invalid topology: StateStore storeName is not added yet.
您似乎只是忘记将状态存储从字面上“添加”到处理拓扑,然后将状态存储附加(“使可用”)到您的Transformer
。
这是一个演示此内容的代码段(对不起,在Java中)。
将状态存储添加到拓扑:
final StreamsBuilder builder = new StreamsBuilder();
final StoreBuilder<KeyValueStore<String, Long> myStateStore =
Stores.keyValueStoreBuilder(
Stores.persistentKeyValueStore("my-state-store-name"),
Serdes.String(),
Serdes.Long())
.withCachingEnabled();
builder.addStateStore(myStateStore);
将状态存储添加到您的Transformer
:
final KStream<String, Double> stream = builder.stream("your-input-topic", Consumed.with(Serdes.String(), Serdes.Double()));
final KStream<String, Long> transformedStream =
stream.transform(new YourTransformer(myStateStore.name()), myStateStore.name());
当然,您的Transformer
必须使用以下代码集成状态存储(此Transformer
读取<String, Double>
并写入String, Long>
)。
class MyTransformer implements TransformerSupplier<String, Double, KeyValue<String, Long>> {
private final String myStateStoreName;
MyTransformer(final String myStateStoreName) {
this.myStateStoreName = myStateStoreName;
}
@Override
public Transformer<String, Double, KeyValue<String, Long>> get() {
return new Transformer<String, Double, KeyValue<String, Long>>() {
private KeyValueStore<String, Long> myStateStore;
private ProcessorContext context;
@Override
public void init(final ProcessorContext context) {
myStateStore = (KeyValueStore<String, Long>) context.getStateStore(myStateStoreName);
}
// ...
}
}