0

我有一个简单的单键值 Map(K,V) myDictionary由我的程序填充,最后我想将它作为 JSON 格式字符串写入文本文件中 - 因为我需要稍后解析它们。

我之前使用过这段代码,

Some(new PrintWriter(outputDir+"/myDictionary.json")).foreach{p => p.write(compact(render(decompose(myDictionary)))); p.close}

我发现随着输入大小的增加它会变慢。后来,我用了这个 var out = new

var out = new PrintWriter(outputDir+"/myDictionary.json");
out.println(scala.util.parsing.json.JSONObject(myDictionary.toMap).toString())

事实证明这有点快。

我已经为样本输入运行了这个,发现这比我之前的方法更快。我假设我的输入映射大小将达到至少一百万个值(> 1GB 文本文件)(K,V),因此我想确保我遵循更快和内存高效的映射序列化过程方法。你还有哪些其他方法会建议,我可以考虑优化这一点。

4

1 回答 1

4

标准 Scala 库中的 JSON 支持可能不是最佳选择。不幸的是,Scala 的 JSON 库的情况有点令人困惑,有很多替代方案(Lift JSON、Play JSON、Spray JSON、Twitter JSON、Argonaut ......),基本上一周中的每一天都有一个库......我建议您至少看看这些,看看它们中的任何一个是否更易于使用和更具表现力。


这是一个使用 Play JSON 的示例,我出于特殊原因选择了该示例(能够使用宏生成格式):

object JsonTest extends App {
  import play.api.libs.json._

  type MyDict = Map[String, Int]

  implicit object MyDictFormat extends Format[MyDict] {
    def reads(json: JsValue): JsResult[MyDict] = json match {
      case JsObject(fields) =>
        val b = Map.newBuilder[String, Int]
        fields.foreach {
          case (k, JsNumber(v)) => b += k -> v.toInt
          case other => return JsError(s"Not a (string, number) pair: $other")
        }
        JsSuccess(b.result())

      case _ => JsError(s"Not an object: $json")
    }

    def writes(m: MyDict): JsValue = {
      val fields: Seq[(String, JsValue)] = m.map {
        case (k, v) => k -> JsNumber(v)
      } (collection.breakOut)

      JsObject(fields)
    }
  }

  val m       = Map("hallo" -> 12, "gallo" -> 34)
  val serial  = Json.toJson(m)
  val text    = Json.stringify(serial)
  println(text)
  val back    = Json.fromJson[MyDict](serial)
  assert(back == JsSuccess(m), s"Failed: $back")
}

虽然您可以直接构造和解构JsValues,但主要思想是使用Format[A]whereA是数据结构的类型。这比标准的 Scala-Library JSON 更加强调类型安全。它看起来更冗长,但最终我认为这是更好的方法。

有一些实用方法Json.toJsonJson.fromJson它们会寻找您想要的类型的隐式格式。

另一方面,它确实在内存中构建了所有内容,并且确实复制了您的数据结构(因为对于 map 中的每个条目,您将拥有另一个 tuple (String, JsValue)),因此这不一定是内存效率最高的解决方案,因为您是运行在 GB 量级...


Jerkson 是 Java JSON 库 Jackson 的 Scala 包装器。后者显然具有流式传输数据的功能。我发现这个项目说它增加了流媒体支持。依次播放 JSON 是基于 Jerkson,所以也许您甚至可以弄清楚如何使用它来流式传输您的对象。另请参阅此问题

于 2013-10-18T09:21:08.300 回答