[英]Clojure: implementing stateful Java interface
Kafka Streams有一個接口, Processor
,其實現是有狀態的。 開發人員指南中給出的示例實現是:
public class WordCountProcessor implements Processor<String, String> {
private ProcessorContext context;
private KeyValueStore<String, Long> kvStore;
@Override
@SuppressWarnings("unchecked")
public void init(ProcessorContext context) {
// keep the processor context locally because we need it in punctuate() and commit()
this.context = context;
// call this processor's punctuate() method every 1000 time units.
this.context.schedule(1000);
// retrieve the key-value store named "Counts"
kvStore = (KeyValueStore) context.getStateStore("Counts");
}
@Override
public void process(String dummy, String line) {
String[] words = line.toLowerCase().split(" ");
for (String word : words) {
Long oldValue = kvStore.get(word);
if (oldValue == null) {
kvStore.put(word, 1L);
} else {
kvStore.put(word, oldValue + 1L);
}
}
}
@Override
public void punctuate(long timestamp) {
KeyValueIterator<String, Long> iter = this.kvStore.all();
while (iter.hasNext()) {
KeyValue<String, Long> entry = iter.next();
context.forward(entry.key, entry.value.toString());
}
iter.close();
// commit the current processing progress
context.commit();
}
@Override
public void close() {
// close the key-value store
kvStore.close();
}
}
init
方法初始化WordCountProcessor
的內部狀態,例如檢索鍵值存儲。 其他方法(如process
和close
)使用此狀態。
這不是我清楚如何reify
Clojure中這樣的接口。 我們如何將init
檢索到的狀態傳遞給process
, close
等?
我有一個想法是使用一個閉包:
(let [ctx (atom nil)]
(reify Processor
(close [this]
;; Do something w/ ctx
)
(init [this context]
(reset! ctx context))
(process [this k v]
;; Do something w/ ctx
)
(punctuate [this timestamp]
;; Do something w/ ctx
)))
令人討厭的是,我們每次都必須從ProcessorContext
對象開始,因此鍵值存儲代碼將在需要鍵值存儲的所有方法中重復。
我沒有看到(通用)方法,雖然根據具體情況,我們可以用方法所需的更具體的狀態替換ctx
原子。
有沒有更好的辦法?
關閉原子將是實現它的主要方式。 您的原始類有兩個字段,因此您可以關閉兩個原子以獲得相同的效果
(let [ctx (atom nil)
kv-store (atom nil)]
(reify Processor
,,,
(init [this context]
(reset! ctx context)
(reset! kv-store (.getStateStore context "Counts")))
,,,))
如果這仍然太乏味,那么你可以添加一些便利函數,這些函數也會關閉原子
(let [ctx (atom nil)
kv-store (atom nil)]
(def kv-get [key]
(.get @kv-store key))
(def kv-all []
(iterator-seq (.all @kv-store)))
(def kv-put [key value]
(.put @kv-store key value))
(reify Processor
,,,
(init [this context]
(reset! ctx context)
(reset! kv-store (.getStateStore context "Counts")))
,,,
(punctuate [this timestamp]
(do-seq [x (kv-all)]
,,,)
)))
替代方案是使用gen-class ,但認為你會更好地使用reify。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.