我正在将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 Map):
{
"abc_123": [
[timestamp1, value1],
[timestamp2, value2]
],
"abd_124": [
[timestamp1, value1],
[timestamp2, value2]
]
}
换句话说,我想为“结果”中的每个传感器“名称”创建一个键,并将此键与此特定传感器“名称”的“值”数组相关联。我现在不需要保存/存储“sample_size”,“tags”和“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。
答案 0 :(得分:3)
与像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
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))))