如何将 PlayJSON 列表转换为 Scala Map(复杂)?

How to convert PlayJSON list to Scala Map (complex)?

我正在将 Python 脚本转换为 Scala,但我遇到了一些问题(请注意,我以前从未用 Scala 编程过)。

我正在向 KairosDB and I'm parsing it's response in Scala with PlayJSON. As you can see in the Query Metrics Documentation 发出 API 请求,KairosDB 以 JSON 响应,如下所示:

{
  "queries": [
      {
          "sample_size": 14368,
          "results": [
              {
                  "name": "abc_123",
                  "group_by": [
                      {
                         "name": "type",
                         "type": "number"
                      },
                      {
                          "name": "tag",
                          "tags": [
                              "host"
                          ],
                          "group": {
                              "host": "server1"
                          }
                      }
                  ],
                  "tags": {
                      "host": [
                          "server1"
                      ],
                      "customer": [
                          "bar"
                      ]
                  },
                  "values": [
                      [
                          1364968800000,
                          11019
                      ],
                      [
                          1366351200000,
                          2843
                      ]
                  ]
              }
          ]
      }
  ]
}

目前我想解析此响应(以 JSON 格式)并创建如下结构(我猜将表示为 Scala Map):

{ 
    "abc_123": [
        [timestamp1, value1], 
        [timestamp2, value2]
     ],
     "abd_124": [
        [timestamp1, value1], 
        [timestamp2, value2]
     ]
}

换句话说,我想为从“结果”获得的每个传感器“名称”创建一个键,并将该键与该特定传感器“名称”的“值”数组相关联。我现在不需要保存/存储“sample_size”、“标签”和“group_by”,因为它对我没用。

目前我正在尝试解决这个问题(记住我正在使用 PlayJSON):

// Get "results" from JSON
val parsedResponse = (((Json.parse(response.body.asString) \ "queries")(0)) \ "results")

// Some commands that I've tested and works:
// Print keys: parsedResponse.foreach { p => print( (p(0)) \ "name" ) }
// Print values: parsedResponse.foreach { p => print((p(0) \ "values")) }

// Here I'm trying to return a Set, but it don't work at all
// val data = parsedResponse.foreach { p => ((p(0)) \ "name").asOpt[String] -> ((p(0) \ "values").asOpt[Seq]) }

请注意,我可以打印 parsedResponse 并得到以下信息:https://gist.github.com/paladini/b474bba6c3711ddcdacd

我如何在 Scala 中实现它?

与像 python 这样的动态语言相反,在 Scala 中我们通常以类型安全的方式做事,包括 json 解析。我们通常不使用字典,我们总是将 json 转换为键入的内容(并且更安全)。

玩的时候,可以按照play文档中的提示,使用play-json

结果是这样的:

import play.api.libs.json._
import play.api.libs.functional.syntax._

case class ResultValue(timestamp: Long, value: Long)
case class Result(name: String, values: Seq[ResultValue])

implicit val resultValueReads: Reads[ResultValue] = (
  (JsPath(0)).read[Long] and
  (JsPath(1)).read[Long]
)(ResultValue.apply _)

implicit val resultReads: Reads[Result] = (
  (JsPath \ "name").read[String] and
  (JsPath \ "values").read[Seq[ResultValue]]
)(Result.apply _)

val parsedResponse = (((Json.parse(text) \ "queries")(0)) \ "results").validate[Seq[Result]]

parsedResponse.asOpt match { 
  case Some(results) => println(results)
  case None => println("Nothing was parsed")
}

打印:

List(Result(abc_123,List(ResultValue(1364968800000,11019), ResultValue(1366351200000,2843))))

那么你可以这样使用它:

results(0).name
results(0).values.timestamp
results(0).values.value

其他选择:json4s

play-json 有点冗长(特别是因为你来自动态语言),所以如果你想要一种更简单的解析方式 json 你可以使用 json4s .解决方案是这样的:

import org.json4s.DefaultFormats
import org.json4s.native.JsonMethods._

implicit val formats = DefaultFormats

case class Result(name: String, values: List[List[Long]])

val json = parse(text)

val results = ((json \ "queries")(0) \ "results").extract[List[Result]]

println(results(0).name)
println(results(0).values)

** 使用 play-json**

的更简洁但更不安全的版本
case class Result(name: String, values: Seq[Seq[Long]])                                                                                                                

implicit val resultReads: Reads[Result] = (
  (JsPath \ "name").read[String] and
  (JsPath \ "values").read[Seq[Seq[Long]]]
)(Result.apply _)

val parsedResponse = (((Json.parse(text) \ "queries")(0)) \ "results").validate[Seq[Result]]

parsedResponse.asOpt match { 
  case Some(results) => println(results)
  case None => println("Nothing was parsed")
}

打印:

List(Result(abc_123,List(List(1364968800000, 11019), List(1366351200000, 2843))))