[英]Akka Stream dynamic Sink depending on Message from Kafka topic
我有一個閱讀 Message 的 Kafka 消費者。 每條消息都有一個 ID 和內容。
case class Message(id: String, content: String)
根據 ID,我想將 Message 寫入單獨的接收器。 具體到 MongoDB 集合中。 Mongo 提供了一個 Sink 將其寫入 DB 到指定的集合中。
val sink: Sink[Document, Future[Done]] = MongoSink.insertOne(collection(id))
問題是,我需要在連接 Kafka 消費者源時指定接收器,但是每個元素都定義了它應該進入哪個接收器 go。 有沒有辦法在元素到達時動態使用特定的接收器。 或者這是不可能的,例如,我應該為每個 id 使用不同的 Kafka 主題並將每個源連接到單獨的接收器?
您的示例中的類型如何排列並不完全清楚(例如Document
和Message
之間的關系),但您可以采取以下幾種方法:
Sink.foreachAsync[Message](parallelism) { msg =>
val document = documentFromMessage(msg)
val collection = collection(msg.id)
Source.single(document).runWith(MongoSink.insertOne(collection))
}
請注意,這將為每條消息使用一個新的 Mongo 接收器,這可能會帶來效率問題。 請注意,如果有一種更輕量級的方式(例如在 reactivemongo 驅動程序中?)在插入單個文檔后返回Future
,但使用連接池之類的東西來減少單個文檔插入的開銷,那可能會更可取。
Partition
和GraphDSL
定義一個包含預構建接收器的接收器// collection0, etc. are predefined and encompass all of the collections which might be returned by collection(id)
val collections: Map[MongoCollection[Document], (Int, Sink[Document, Future[Done]])] = Map(
collection0 -> (0 -> MongoSink.insertOne(collection0)),
collection1 -> (1 -> MongoSink.insertOne(collection1)),
collection2 -> (2 -> MongoSink.insertOne(collection2)),
collection3 -> (3 -> MongoSink.insertOne(collection3))
)
val combinedSink = Sink.fromGraph(GraphDSL.create() { implicit builder =>
import GraphDSL.Implicits._
val partition = builder.add(
Partition[Message](
collections.size,
{ msg => collections(collection(msg.id))._1 }
)
)
val toDocument = Flow[Message].map(documentFromMessage)
collections.foreach {
case (_, (n, sink)) =>
partition.out(n) ~> toDocument ~> sink
}
SinkShape.of(partition.in)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.