【问题标题】:Processing an akka stream asynchronously and writing to a file sink异步处理 akka 流并写入文件接收器
【发布时间】:2019-04-11 18:01:50
【问题描述】:

我正在尝试编写一段代码,该代码将使用一系列代码(公司的证券交易所代码)并从每个代码的 REST API 中获取公司信息。

我想异步获取多家公司的信息。

我想以连续的方式将结果保存到文件中,因为整个数据集可能无法放入内存。

根据我能够在谷歌上搜索到的关于这个主题的 akka 流和资源的文档,我提出了以下代码(为简洁起见,省略了某些部分):

  implicit val actorSystem: ActorSystem = ActorSystem("stock-fetcher-system")
  implicit val materializer: ActorMaterializer = ActorMaterializer(None, Some("StockFetcher"))(actorSystem)
  implicit val context = system.dispatcher

  import CompanyJsonMarshaller._
  val parallelism = 10
  val connectionPool = Http().cachedHostConnectionPoolHttps[String](s"api.iextrading.com")
  val listOfSymbols = symbols.toList

  val outputPath = "out.txt"  


  Source(listOfSymbols)
    .mapAsync(parallelism) {
      stockSymbol => Future(HttpRequest(uri = s"https://api.iextrading.com/1.0/stock/${stockSymbol.symbol}/company"), stockSymbol.symbol)
    }
    .via(connectionPool)
    .map {
      case (Success(response), _) => Unmarshal(response.entity).to[Company]
      case (Failure(ex), symbol)       => println(s"Unable to fetch char data for $symbol") "x"
    }
    .runWith(FileIO.toPath(new File(outputPath).toPath, Set(StandardOpenOption.APPEND)))
    .onComplete { _ =>
      bufferedSource.close
      actorSystem.terminate()
    }

这是有问题的行:

runWith(FileIO.toPath(new File(outputPath).toPath, Set(StandardOpenOption.APPEND)))

它没有编译,编译器给了我这个看起来很神秘的错误:

Type mismatch, expected Graph[SinkShape[Any, NotInferedMat2], actual Sink[ByeString, Future[IOResult]]

如果我将接收器更改为 Sink.ignore 或 println(_) 它可以工作。

我希望得到更详细的解释。

【问题讨论】:

    标签: scala akka akka-stream


    【解决方案1】:

    正如编译器所指出的,类型不匹配。在调用.map...

    .map {
      case (Success(response), _) =>
        Unmarshal(response.entity).to[Company]
      case (Failure(ex), symbol)  =>
        println(s"Unable to fetch char data for $symbol")
        "x"
    }
    

    ...您返回Company 实例或String,因此编译器推断最接近的超类型(或“最小上限”)为AnySink 需要 ByteString 类型的输入元素,而不是 Any

    一种方法是在不解组响应的情况下将响应发送到文件接收器:

    Source(listOfSymbols)
      .mapAsync(parallelism) {
        ...
      }
      .via(connectionPool)
      .map(_.entity.dataBytes) // entity.dataBytes is a Source[ByteString, _]
      .flatMapConcat(identity)
      .runWith(FileIO.toPath(...))
    

    【讨论】:

    • 感谢map 语句返回类型Any 和接收器期望ByteString 的提示。我实际上忘记从第二个案例语句中删除"x",但无论如何,单位和公司可能与ByteString 不同。至于答案的其余部分——将ByteString 写入文件会改变程序的语义,因为它不再是人类可读的,其次flatMapConcat(identity) 有什么作用?
    猜你喜欢
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-10
    • 2016-09-05
    相关资源
    最近更新 更多