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

2024-04-16 18:18:31 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我向KairosDB发出一个API请求,并用PlayJSON在Scala中解析它的响应。正如您所看到的in the Query Metrics Documentation,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映射表示):

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

换句话说,我想为从“results”中得到的每个传感器“name”创建一个键,并将这个键与这个特定传感器“name”的“values”数组相关联。我现在不需要保存/存储“样本大小”、“标签”和“分组依据”,因为这对我没用。你知道吗

目前,我正在尝试用这个来解决问题(请记住,我使用的是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中实现这一点?


Tags: namejsonhosttypetagsgroupresultsvalues
1条回答
网友
1楼 · 发布于 2024-04-16 18:18:31

与python等动态语言不同,在Scala中,我们通常以类型安全的方式进行操作,包括json解析。我们通常不使用字典,我们总是将json转换成某种类型的(更安全的)。你知道吗

在游戏中,您可以按照游戏文档中的建议,使用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

playjson有点冗长(特别是因为您来自一种动态语言),所以如果您想更简单地解析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))))

相关问题 更多 >