kafkaストリームアプリケーションがあり、トピックに関するレコードの公開を待機していますuser_activity
。 jsonデータを受け取り、キーに対する値に応じて、そのストリームをさまざまなトピックにプッシュします。
これは私のストリームのAppコードです:
KStream<String, String> source_user_activity = builder.stream("user_activity");
source_user_activity.flatMapValues(new ValueMapper<String, Iterable<String>>() {
@Override
public Iterable<String> apply(String value) {
System.out.println("value: " + value);
ArrayList<String> keywords = new ArrayList<String>();
try {
JSONObject send = new JSONObject();
JSONObject received = new JSONObject(value);
send.put("current_date", getCurrentDate().toString());
send.put("activity_time", received.get("CreationTime"));
send.put("user_id", received.get("UserId"));
send.put("operation_type", received.get("Operation"));
send.put("app_name", received.get("Workload"));
keywords.add(send.toString());
// apply regex to value and for each match add it to keywords
} catch (Exception e) {
// TODO: handle exception
System.err.println("Unable to convert to json");
e.printStackTrace();
}
return keywords;
}
}).to("user_activity_by_date");
このコードでは、操作の種類を確認し、それに応じて、ストリームを関連トピックにプッシュします。
どうすればこれを達成できますか?
編集:
私はコードをこれに更新しました:
final StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> source_o365_user_activity = builder.stream("o365_user_activity");
KStream<String, String>[] branches = source_o365_user_activity.branch(
(key, value) -> (value.contains("Operation\":\"SharingSet") && value.contains("ItemType\":\"File")),
(key, value) -> (value.contains("Operation\":\"AddedToSecureLink") && value.contains("ItemType\":\"File")),
(key, value) -> true
);
branches[0].to("o365_sharing_set_by_date");
branches[1].to("o365_added_to_secure_link_by_date");
branches[2].to("o365_user_activity_by_date");
ストリームを分割するには、branch
メソッドを使用できます。このメソッドは、ソースストリームをいくつかのストリームに分割するための述語を取ります。
以下のコードは kafka-streams-examples から取得されます:
KStream<String, OrderValue>[] forks = ordersWithTotals.branch(
(id, orderValue) -> orderValue.getValue() >= FRAUD_LIMIT,
(id, orderValue) -> orderValue.getValue() < FRAUD_LIMIT);
forks[0].mapValues(
orderValue -> new OrderValidation(orderValue.getOrder().getId(), FRAUD_CHECK, FAIL))
.to(ORDER_VALIDATIONS.name(), Produced
.with(ORDER_VALIDATIONS.keySerde(), ORDER_VALIDATIONS.valueSerde()));
forks[1].mapValues(
orderValue -> new OrderValidation(orderValue.getOrder().getId(), FRAUD_CHECK, PASS))
.to(ORDER_VALIDATIONS.name(), Produced
.with(ORDER_VALIDATIONS.keySerde(), ORDER_VALIDATIONS.valueSerde()));
オリジナル KStream.branch
メソッドは、配列とジェネリックが混在しているため、また「マジックナンバー」を使用して結果から正しいブランチを抽出することを強制するため、不便です(例: KAFKA-5488 問題を参照)。 spring-kafka 2.2.4以降、 KafkaStreamBrancher クラスが使用可能になります。これにより、より便利な分岐が可能になります。
new KafkaStreamsBrancher<String, String>()
.branch((key, value) -> value.contains("A"), ks->ks.to("A"))
.branch((key, value) -> value.contains("B"), ks->ks.to("B"))
.defaultBranch(ks->ks.to("C"))
.onTopOf(builder.stream("source"))
//onTopOf returns the provided stream so we can continue with method chaining
//and do something more with the original stream
KIP-418 もあるので、そのようなクラスがKafka自体に現れる可能性もあります。
別の可能性は、TopicNameExtractorを使用してイベントを動的にルーティングすることです:
https://www.confluent.io/blog/putting-events-in-their-place-with-dynamic-routing
ただし、事前にトピックを作成しておく必要があります。
val outputTopic: TopicNameExtractor[String, String] = (_, value: String, _) => defineOutputTopic(value)
builder
.stream[String, String](inputTopic)
.to(outputTopic)
また、defineOutputTopicは、値(またはキーまたはレコードコンテキスト)を指定すると、定義されたトピックのセットの1つを返すことができます。 PD:scalaコードの場合は申し訳ありません。リンクにJavaの例があります。