Scala Akka Streams过滤器和;按键集合分组
我有一条小溪Scala Akka Streams过滤器和;按键集合分组,scala,akka,akka-stream,reactive-streams,Scala,Akka,Akka Stream,Reactive Streams,我有一条小溪 case class Msg(keys: Seq[Char], value: String) 现在,我想筛选一个子集的关键,例如。 val filterKeys=Set[Char]('k','f','c')和过滤器(k.exists(filterKeys.contains)) 然后分割这些键,使某些键通过不同的流进行处理,最后再合并到一起 /-key=k-> f1 --\ Source[Msg] ~>
case class Msg(keys: Seq[Char], value: String)
现在,我想筛选一个子集的关键,例如。
val filterKeys=Set[Char]('k','f','c')
和过滤器(k.exists(filterKeys.contains))
然后分割这些键,使某些键通过不同的流进行处理,最后再合并到一起
/-key=k-> f1 --\
Source[Msg] ~> Filter ~> router |--key=f-> f2 ----> Merge --> f4
\-key=c-> f3 --/
我该怎么做呢
FlexiRoute
以旧的方式似乎是一个不错的选择,但在新的API中,我想我要么制作一个自定义的GraphStage
,要么从DSL创建我自己的图形,因为我认为没有办法通过内置的阶段来实现这一点。小型密钥集解决方案
如果密钥集很小且不可变,那么广播和过滤器的组合可能是最容易理解的实现。首先需要定义所描述的过滤器:
def goodKeys(keySet : Set[Char]) = Flow[Msg] filter (_.keys exists keySet.contains)
然后,它可以如上所述向广播公司提供信息。所有具有良好键的Msg
值都将广播到三个过滤器中的每一个,每个过滤器只允许一个特定键:
val g = RunnableGraph.fromGraph(GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>
import GraphDSL.Implicits._
val source : Source[Msg] = ???
val goodKeyFilter = goodKeys(Set('k','f','c'))
val bcast = builder.add(BroadCast[Msg](3))
val merge = builder.add(Merge[Msg](3))
val kKey = goodKeys(Set('k'))
val fKey = goodKeys(Set('f'))
val cKey = goodKeys(Set('c'))
//as described in the question
val f1 : Flow[Msg, Msg, _] = ???
val f2 : Flow[Msg, Msg, _] = ???
val f3 : Flow[Msg, Msg, _] = ???
val f4 : Sink[Msg,_] = ???
source ~> goodKeyFilter ~> bcast ~> kKey ~> f1 ~> merge ~> f4
bcast ~> fKey ~> f2 ~> merge
bcast ~> cKey ~> f3 ~> merge
大密钥集解决方案
如果密钥集很大,则groupBy更好。假设您有一个函数键的映射
:
//e.g. 'k' -> f1
val keyFuncs : Map[Set[Char], (Msg) => Msg]
此映射可与groupBy函数一起使用:
source
.via(goodKeys(Set('k','f','c'))
.groupBy(keyFuncs.size, _.keys)
.map(keyFuncs(_.keys)) //apply one of f1,f2,f3 to the Msg
.mergeSubstreams