[英]Parsing nodes on JSON with Scala -
我被要求解析一个JSON文件,以获取用户输入的超过指定速度的所有总线。
JSON文件可以在这里下载
就像这样:
{
"COLUMNS": [
"DATAHORA",
"ORDEM",
"LINHA",
"LATITUDE",
"LONGITUDE",
"VELOCIDADE"
],
"DATA": [
[
"04-16-2015 00:00:55",
"B63099",
"",
-22.7931,
-43.2943,
0
],
[
"04-16-2015 00:01:02",
"C44503",
781,
-22.853649,
-43.37616,
25
],
[
"04-16-2015 00:11:40",
"B63067",
"",
-22.7925,
-43.2945,
0
],
]
}
问题是:我对scala很陌生,之前从未与json合作过(对我感到羞耻)。 我需要的是从DATA节点获取“Ordem”,“Linha”和“Velocidade”。
我创建了一个case类来封装所有数据,以便以后查找那些超过指定速度的数据。
case class Bus(ordem: String, linha: Int, velocidade: Int)
我这样做是将文件作为textFile和spliting来读取。 虽然这样,我需要预先知道文件的内容,以便在DATA节点之后转到行。
我想知道如何使用JSON解析器执行此操作。 我尝试了很多解决方案,但我无法适应我的问题,因为我需要从DATA节点中提取所有行而不是一个节点内的节点。
谁能帮我?
PS:对不起我的英语,不是母语人士。
首先,您需要了解不同的JSON数据类型。 JSON中的基本类型是数字,字符串,布尔值,数组和对象。 示例中返回的数据是一个具有两个键的对象: COLUMNS
和DATA
。 COLUMNS
键的值为字符串和数字的数组。 DATA
键的值是字符串数组的数组。
您可以使用PlayJSON之类的库来处理此类数据:
val js = Json.parse(x).as[JsObject]
val keys = (js \ "COLUMNS").as[List[String]]
val values = (js \ "DATA").as[List[List[JsValue]]]
val busses = values.map(valueList => {
val keyValues = (keys zip valueList).toMap
for {
ordem <- keyValues("ORDEM").asOpt[String]
linha <- keyValues("LINHA").asOpt[Int]
velocidade <- keyValues("VELOCIDADE").asOpt[Int]
} yield Bus(ordem, linha, velocidade)
})
请注意在将属性转换为预期类型时使用asOpt
。 如果可能,此运算符将键值转换为提供的类型(包含在Some
),否则返回None
。 因此,如果要提供默认值而不是忽略其他结果,则可以使用keyValues("LINHA").asOpt[Int].getOrElse(0)
。
您可以在其文档中阅读有关此处使用的Play JSON方法的更多信息,例如\\
和as
,以及asOpt
。
您可以使用Spark SQL来实现它。 在JSON数据集请参阅节在这里
实质上,使用spark API加载JSON并将其注册为临时表。 您可以从那里在表上运行SQL查询。
正如在@Ben Reich的回答中看到的那样,代码效果很好。 非常感谢你。
虽然,我的Json在“Linha”上有一些类型问题。 正如我在问题上的JSON
示例中可以看到的那样,有“”和数字,例如781。
当尝试执行keyValues("LINHA").asOpt[Int].getOrElse(0)
,它产生了一个错误,指出value flatMap is not a member of Int
。 所以,我不得不改变一些事情:
case class BusContainer(ordem: String, linha: String, velocidade: Int)
val jsonString = fromFile("./project/rj_onibus_gps.json").getLines.mkString
val js = Json.parse(jsonString).as[JsObject]
val keys = (js \ "COLUMNS").as[List[String]]
val values = (js \ "DATA").as[List[List[JsValue]]]
val buses = values.map(valueList => {
val keyValues = (keys zip valueList).toMap
println(keyValues("ORDEM"),keyValues("LINHA"),keyValues("VELOCIDADE"))
for {
ordem <- keyValues("ORDEM").asOpt[String]
linha <- keyValues("LINHA").asOpt[Int].orElse(keyValues("LINHA").asOpt[String])
velocidade <- keyValues("VELOCIDADE").asOpt[Int]
} yield BusContainer(ordem, linha.toString, velocidade)
})
谢谢您的帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.