将Akka Source转换为Spark InputDStream的惯用法

时间:2016-02-27 12:14:01

标签: scala apache-spark akka spark-streaming akka-stream

我基本上试图与this question中提出的问题相反;也就是说,使用Source[A]将元素推送到InputDStream[A]

到目前为止,我已经设法破坏了一个使用Feeder actor和一个类似于ActorWordCount example的Receiver actor的实现,但这看起来有点复杂所以我很好奇有一种更简单的方法。

2 个答案:

答案 0 :(得分:1)

编辑:由于没有好的答案,5天后自我接受。

我已将基于Actor的实现提取到lib Sparkka-streams中,到目前为止它一直在为我工作。当更好地解决这个问题时,我会更新或弃用lib。

其用法如下:

// InputDStream can then be used to build elements of the graph that require integration with Spark
val (inputDStream, feedDInput) = Streaming.connection[Int]()
val source = Source.fromGraph(GraphDSL.create() { implicit builder =>

  import GraphDSL.Implicits._

  val source = Source(1 to 10)

  val bCast = builder.add(Broadcast[Int](2))
  val merge = builder.add(Merge[Int](2))

  val add1 = Flow[Int].map(_ + 1)
  val times3 = Flow[Int].map(_ * 3)
  source ~> bCast ~> add1 ~> merge
            bCast ~> times3 ~> feedDInput ~> merge

  SourceShape(merge.out)
})

val reducedFlow = source.runWith(Sink.fold(0)(_ + _))
whenReady(reducedFlow)(_ shouldBe 230)

val sharedVar = ssc.sparkContext.accumulator(0)
inputDStream.foreachRDD { rdd =>
  rdd.foreach { i =>
    sharedVar += i
  }
}
ssc.start()
eventually(sharedVar.value shouldBe 165)

答案 1 :(得分:0)

参考:http://spark.apache.org/docs/latest/streaming-custom-receivers.html

你可以这样做:

class StreamStopped extends RuntimeException("Stream stopped")

// Serializable factory class
case class SourceFactory(start: Int, end: Int) {
  def source = Source(start to end).map(_.toString)
}

class CustomReceiver(sourceFactory: SourceFactory)
  extends Receiver[String](StorageLevel.MEMORY_AND_DISK_2) with Logging {

  implicit val materializer = ....

  def onStart() {
    sourceFactory.source.runForEach { e =>
      if (isStopped) {
        // Stop the source
        throw new StreamStopped
      } else {
        store(e)
      }
    } onFailure {
      case _: StreamStopped => // ignore
      case ex: Throwable => reportError("Source exception", ex)
    }
  }

  def onStop() {}
}

val customReceiverStream = ssc.receiverStream(new CustomReceiver(SourceFactory(1,100))