繁体   English   中英

使用 Scala 和 JSON4S 解析大型 JSON 文件

[英]Parsing large JSON file with Scala and JSON4S

我正在使用 IntelliJ IDEA 15 中的 Scala 并尝试解析大型 twitter 记录 json 文件并计算主题标签的总数。 我对 Scala 和函数式编程的想法非常陌生。 json 文件中的每一行都是一个 json 对象(代表一条推文)。 文件中的每一行都是这样开始的:

{"in_reply_to_status_id":null,"text":"To my followers sorry..
{"in_reply_to_status_id":null,"text":"#victory","in_reply_to_screen_name"..
{"in_reply_to_status_id":null,"text":"I'm so full I can't move"..

我对一个名为“entities”的属性最感兴趣,它包含一个名为“hastags”的属性和一个标签列表。 这是一个例子:

"entities":{"hashtags":[{"text":"thewayiseeit","indices":[0,13]}],"user_mentions":[],"urls":[]},

我浏览了用于解析 json 的各种 scala 框架,并决定使用 json4s。 我的 Scala 脚本中有以下代码。

    import org.json4s.native.JsonMethods._

    var json: String = ""
    for (line <- io.Source.fromFile("twitter38.json").getLines) json += line
    val data = parse(json)

我的逻辑是我试图将 twitter38.json 中的每一行读入一个字符串,然后用 parse() 解析整个字符串。 parse 函数抛出错误声明:

“类型不匹配,预期:无,找到:字符串。”

我已经看到在包含 json 对象的字符串上使用 parse() 的示例,例如

val jsontest =
"""{
    |"name" : "bob",
    |"age" : "50",
    |"gender" : "male"
    |}
""".stripMargin
val data = parse(jsontest)

但我收到了同样的错误。 我来自面向对象的编程背景,我处理这个问题的方式有什么根本错误吗?

您很可能已将对Intellij项目或模块的依赖项错误地导入了文件中。 确保已导入以下行:

import org.json4s.native.JsonMethods._

即使您正确导入了此模块, parse(String: json)也不适合您,因为您错误地形成了json。 您的json字符串将如下所示:

"""{"in_reply_...":"someValue1"}{"in_reply_...":"someValues2"}"""

但应如下所示,它是可以解析的有效json:

"""{{"in_reply_...":"someValue1"},{"in_reply_...":"someValues2"}}"""

也就是说,您需要json的开头和结尾括号,以及每行tweet之间的逗号。 请阅读json4s文档以获取更多信息。

虽然已经快 6 岁了,但我认为这个问题值得再试一次。

JSON格式在人们的脑海中存在一些误解,尤其是它们的存储方式和回读方式。

JSON 文档存储为具有所有其他字段的单个对象,或者可能以相同格式存储的多个对象的数组。 第二部分很重要,因为几乎每种编程语言中的数组都是由尖括号定义的,值由逗号分隔(注意这里我使用了一个人对象作为我的单个值):

[
 {"name":"John","surname":"Doe"},
 {"name":"Jane","surname":"Doe"}
]

还要注意,除了括号、数字和布尔值之外的所有内容在写入文件时都用引号引起来。

然而,还有另一种用途不是官方的,但更喜欢轻松传输数据集,其中每个对象或文档(如 nosql/mongo 语言)都存储在新行中,如下所示:

{"name":"John","surname":"Doe"}
{"name":"Jane","surname":"Doe"}

所以对于这个问题,OP 有一个以第二种形式编写的文档,但尝试使用一种算法来读取第一种形式。 以下代码几乎没有简单的更改来实现这一点,用户必须阅读文件知道:

    var json: String = "["
    for (line <- io.Source.fromFile("twitter38.json").getLines) json += line + ","
    json=json.splitAt(json.length()-1)._1
    json+= "]"
    val data = parse(json)

PS:虽然@sbrannon 的想法是正确的,但他/她给出的示例错误地用大括号而不是尖括号来包围数据。

编辑:我添加了json=json.splitAt(json.length()-1)._1因为上面的代码以逗号结尾,这将导致每个 JSON 格式定义的解析错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM