【问题标题】:Read a huge json array file of objects读取一个巨大的 json 对象数组文件
【发布时间】:2020-07-01 09:58:40
【问题描述】:

我有一个很大的 json 文件,大小约为 40Gb。当我尝试将此对象数组文件转换为 java 对象列表时,它崩溃了。我已经使用了所有大小的最大堆 xmx,但没有任何效果!

public Set<Interlocutor> readJsonInterlocutorsToPersist() {
    String userHome = System.getProperty(USER_HOME);
    log.debug("Read file interlocutors "+userHome);
    try {
        ObjectMapper mapper = new ObjectMapper();
        // JSON file to Java object
        Set<Interlocutor> interlocutorDeEntities = mapper.readValue(
                new File(userHome + INTERLOCUTORS_TO_PERSIST),
                new TypeReference<Set<Interlocutor>>() {
                });
        return interlocutorDeEntities;
    } catch (Exception e) {
        log.error("Exception while Reading InterlocutorsToPersist file.",
                e.getMessage());
        return null;
    }
} 

有没有办法使用BufferedReader 读取此文件,然后逐个对象推送?

【问题讨论】:

  • 如果是 40GB 的 JSON,我怀疑整个数据集是否适合您的记忆。甚至曾经反序列化为一组对象。
  • 可以用JsonParser.nextToken()编写你的自我解析器
  • 流式 API 可用如下:sites.google.com/site/gson/streaming 这些将在将字符串数据 (json) 反编译为 Java 对象后立即处理。
  • 为什么需要它作为对象列表?

标签: java jackson fasterxml


【解决方案1】:

您绝对应该看看 Jackson Streaming API (https://www.baeldung.com/jackson-streaming-api)。我自己用它来处理 GB 的大型 JSON 文件。最棒的是您可以将您的 JSON 分成几个较小的 JSON 对象,然后使用 mapper.readTree(parser) 解析它们。这样您就可以将普通 Jackson 的便利性与 Streaming API 的速度和可扩展性结合起来。

与您的问题有关:

我知道您有一个非常大的数组(这是文件大小的原因)和一些可读性更强的对象:

例如:

[ // 40GB
{}, // Only 400 MB
{},
]

您现在可以做的是使用 Jackson 的 Streaming API 解析文件并遍历数组。但是每个单独的对象都可以被解析为“常规”Jackson 对象,然后轻松处理。

你可以看看这个Use Jackson To Stream Parse an Array of Json Objects,它实际上非常符合你的问题。

【讨论】:

  • 您的解决方案也可以,但是我的对象有很多依赖项(其他对象中的对象),这就是为什么我需要一种方法来读取并转换为对象。谢谢
  • 使用此解决方案,您还可以将所有对象读入一个集合。它实际上与您找到的解决方案相同,但不是使用Gson,而是使用Jackson
【解决方案2】:

有没有办法使用 BufferedReader 读取这个文件然后推送 逐个对象?

当然不是。即使您可以打开此文件,如何将 40GB 作为 java 对象存储在内存中?我认为您的计算机中没有这么多的内存(但从技术上讲,使用ObjectMapper 您应该有大约 2 倍的操作内存 - 40GB 用于存储 json + 40GB 用于将结果存储为 java 对象 = 80 GB)。

我认为您应该使用questions 中的任何方式,但将信息存储在数据库或文件中而不是内存中。例如,如果您在 json 中有数百万行,您应该解析每一行并将其保存到数据库中,而不是将其全部保存在内存中。然后你就可以一步步从数据库中获取这些数据(例如每次不超过1GB)。

【讨论】:

  • 嗯,这在理论上是可能的,正如 SAX(用于 XML)所证明的那样。当然,您不能一次将整个文档放在内存中,但您可以读取结构的一部分,将它们写入数据库/单个对象的较小文档中,将它们从内存中删除,然后重复。不过,我不知道有什么实现可以做到这一点。
猜你喜欢
  • 1970-01-01
  • 2021-05-29
  • 2019-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多