Kafka Streams+SpringBoot之探索:統計計數 - mydeveloperplanet

banq發表於2019-10-17

本示例接上一個案例,其中有傳送訊息的案例,這裡只是消費者舉例,我們將從Tweets my-kafka-streams-topic中讀取流,建立一個以#標籤為值的新中間流,將其轉換存都KTable,包含每個#標籤的數量,然後將其釋出到topic my-kafka-streams-out2。這是一個Ktable。

我們向kafkaprocessingplanet模組新增了一個新的REST端點。我們將閱讀同一主題my-kafka-streams-topic,並將其進行轉換,實現主題標籤作為key和計數作為值,釋出訊息到my-kafka-streams-hashtagcount-output。我們假定訊息中始終有一個#號標籤,並且它在訊息的末尾出現,只是為了使事情簡單。

Kafka屬性與第一個示例相同,不同之處在於我們確實提供了key的序列化/反序列化的配置,因為我們將釋出一個以String作為key的主題。否則,您將遇到ClassCastException。

props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());


首先,我們將建立一個新標籤流,該流將僅包含主題標籤作為值。這可以透過以下方式實現:

KStream<Object, String> hashTags = source.flatMapValues(new ValueMapper<String, Iterable>() {
    @Override
    public Iterable apply(String value) {
      return Arrays.asList(value.substring(value.indexOf("#")));
    }
});


為了簡潔起見,我們將其轉換為lambda:

KStream<Object, String> hashTags = source.flatMapValues((ValueMapper<String, Iterable>) value -> Arrays.asList(value.substring(value.indexOf("#"))));


我們有一個流,其中沒有鍵key和主題標籤作為值。為了知道某個標籤在流中出現多少次,我們需要每個標籤的記錄。因此,我們建立一個KGroupedStream帶有標籤作為鍵key和標籤為值。將KeyValueMapper用於建立keyy。我們將原始鍵和值作為輸入引數提供給apply方法,並將新鍵作為返回String。

KGroupedStream<String, String> hashTags = source.flatMapValues((ValueMapper<String, Iterable>) value -> Arrays.asList(value.substring(value.indexOf("#"))))
  .groupBy(new KeyValueMapper<Object, String, String>() {
      @Override
      public String apply(Object key, String value) {
        return value;
      }
});

同樣,我們將其轉換為lambda:

KGroupedStream<String, String> hashTags = source.flatMapValues((ValueMapper<String, Iterable>) value -> Arrays.asList(value.substring(value.indexOf("#")))) 
  .groupBy((key, value) -> value)


接下來,我們呼叫的KGroupedStream的count方法,將為KTable counts我們建立一個標籤,標籤為鍵,計數為值。

KTable<String, Long> counts = source.flatMapValues((ValueMapper<String, Iterable>) value -> Arrays.asList(value.substring(value.indexOf("#"))))
  .groupBy((key, value) -> value)
  .count();


現在我們唯一需要做的就是建立一個流,並將其釋出到主題my-kafka-streams-hashtagcount-output。

source.flatMapValues((ValueMapper<String, Iterable>) value -> Arrays.asList(value.substring(value.indexOf("#"))))
  .groupBy((key, value) -> value)
  .count()
  .toStream()
  .to("my-kafka-streams-hashtagcount-output", Produced.with(Serdes.String(), Serdes.Long()));


最後,我們需要新增以下內容以啟動流:

final Topology topology = builder.build();
streams2 = new KafkaStreams(topology, props);
streams2.start();


輸出主題必須配置為啟用日誌壓縮。請參閱官方文件簡短說明以瞭解日誌壓縮。日誌壓縮可確保將多個具有相同鍵的記錄釋出到某個主題時,僅保留最新版本。僅最後一個版本有用,如果未啟用日誌壓縮,則舊版本將消耗不必要的資源。啟用日誌壓縮後,Kafka將清除較舊的版本。有了這些資訊,我們可以建立輸出主題:

$ ./kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic my-kafka-streams-hashtagcount-output --config "cleanup.policy=compact"


測試所有內容了。像以前一樣啟動Producer和Processor Spring Boot應用程式。

過呼叫URL http:// localhost:8081 / sendMessages /將訊息從生產者傳送到my-kafka-streams-topic;透過呼叫URL http:// localhost:8082 / startProcessing2 /來啟動流處理器。

使用一些額外的屬性啟動主題的使用者,以便將資料正確列印到控制檯。我們注意到每隔30秒就會有新結果列印到控制檯。

$ ./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-kafka-streams-hashtagcount-output --property print.key=true --value-deserializer=org.apache.kafka.common.serialization.LongDeserializer
italy 85
latin 84
cicero 100
caesar 87


除了使用count方法之外,我們還可以使用以下方法:

count(Materialized.<String, Long, KeyValueStore<Bytes, byte[]>>as("counts-store"))


在這種情況下,結果將儲存在可以查詢的狀態儲存中。如何查詢這些狀態儲存可以在這裡找到。
帖子中使用的資源當然可以在GitHub上找到

 

相關文章