Akka Stream Option输出

时间:2016-12-06 09:33:01

标签: scala akka akka-stream

我创建了一个简单的SourceFlowSink的Akka Stream。有了这个,我可以轻松地通过它发送元素。现在我想更改此流,以便Flow返回Option。取决于Option的结果,我想更改Flow的输出。

enter image description here

是否可以创建这样的结构?

3 个答案:

答案 0 :(得分:8)

此时给出的答案都涉及Broadcast。请注意,它可能适用于此特定示例,但在更复杂的图表中Broadcast可能不是一个明智的选择。 原因是如果至少有一个下游背压,Partition总是背压。 最好的背压感知解决方案是 def splittingSink[T, M1, M2, Mat](f: T ⇒ Option[T], someSink: Sink[T, M1], noneSink: Sink[None.type, M2], combineMat: (M1, M2) ⇒ Mat): Sink[T, Mat] = { val graph = GraphDSL.create(someSink, noneSink)(combineMat) { implicit builder ⇒ (sink1, sink2) ⇒ { import GraphDSL.Implicits._ def partitioner(o: Option[T]) = o.map(_ => 0).getOrElse(1) val partition = builder.add(Partition[Option[T]](2, partitioner)) partition.out(0) ~> Flow[Option[T]].collect { case Some(t) ⇒ t } ~> sink1.in partition.out(1) ~> Flow[Option[T]].collect { case None ⇒ None } ~> sink2.in val mapper = builder.add(Flow.fromFunction(f)) mapper.out ~> partition.in SinkShape(mapper.in) } } Sink.fromGraph(graph) } ,它能够从分区器功能选择的分支中选择性地传播背压。

以下示例(详细说明T-Fowl的答案之一)

SELECT T.* FROM T
         JOIN U on T.x = U.x
WHERE U.a = ? AND U.b BETWEEN ? AND ?
ORDER BY T.x, T.y

答案 1 :(得分:4)

假设你有类似的东西

val source = Source(1 to 100)
val flow = Flow[Int].map {
  case x if x % 2 == 0 ⇒ Some(x.toString)
  case _ ⇒ None
}
val sink1 = Sink.foreach[String](println)
val sink2 = Sink.foreach[None.type](x ⇒ println("dropped element"))

您可以制作具有所需结构的可运行图表,如下所示:

val runnable = source
  .via(flow)
  .alsoTo(Flow[Option[String]].collect { case None ⇒ None }.to(sink2))
  .to(Flow[Option[String]].collect { case Some(x) ⇒ x }.to(sink1))

答案 2 :(得分:3)

您可以将2个水槽视为水槽本身。为了构建更复杂的图表,我们可以使用GraphDSL中提供的函数。

在一般情况下考虑

def splittingSink[T, M1, M2, Mat](f: T ⇒ Option[T], someSink: Sink[T, M1], noneSink: Sink[None.type, M2], combineMat: (M1, M2) ⇒ Mat): Sink[T, Mat] = {
    val graph = GraphDSL.create(someSink, noneSink)(combineMat) { implicit builder ⇒
        (sink1, sink2) ⇒ {
            import GraphDSL.Implicits._

            //Here we broadcast the Some[T] values to 2 flows,
            // each filtering to the correct type for each sink
            val bcast = builder.add(Broadcast[Option[T]](2))
            bcast.out(0) ~> Flow[Option[T]].collect { case Some(t) ⇒ t } ~> sink1.in
            bcast.out(1) ~> Flow[Option[T]].collect { case None ⇒ None } ~> sink2.in

            //The flow that maps T => Some[T]
            val mapper = builder.add(Flow.fromFunction(f))
            mapper.out ~> bcast.in

            //The whole thing is a Sink[T]
            SinkShape(mapper.in)
        }
    }
    Sink.fromGraph(graph)
}

这将返回Sink[T,Mat],使用提供的函数将传入的T元素映射到Option[T],然后将其定向到其中一个提供的接收器。

用法示例:

val sink = splittingSink(
    (s: String) ⇒ if (s.length % 2 == 0) Some(s) else None,
    Sink.foreach[String](s),
    Sink.foreach[None.type](_ ⇒ println("None")),
    (f1: Future[_], f2: Future[_]) ⇒ Future.sequence(Seq(f1, f2)).map(_ ⇒ Done)
)

Source(List("One", "Two", "Three", "Four", "Five", "Six"))
        .runWith(sink)
        .onComplete(_ ⇒ println("----\nDone"))

输出:

None
None
None
Four
Five
None
----
Done

有关Stream Graphs的文档部分将进一步讨论GraphDSL的用法。