Прочитайте огромный файл массива json объектов

У меня есть большой файл размером 40 ГБ, когда я пытаюсь преобразовать этот json-файл массива объектов в список объектов 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, а затем нажать объект за объектом?

Редактировать :

я нашел РЕШЕНИЕ от @Viacheslav:

public Set<Interlocutor> readJsonInterlocutorsToPersist() throws IOException {
        String userHome = System.getProperty(USER_HOME);
        log.debug("readJsonInterlocutorsToPersist file");
        JsonReader reader = new JsonReader(new InputStreamReader(new FileInputStream(userHome + INTERLOCUTORS_TO_PERSIST), "UTF-8"));
        Set<Interlocutor> interlocutorDeEntities = new HashSet<Interlocutor>();
        reader.beginArray();
        Gson gson =  new GsonBuilder()
        .registerTypeAdapter(Date.class, UnixEpochDateTypeAdapter.getUnixEpochDateTypeAdapter())
        .create();
        int i = 0;
        while (reader.hasNext()) {
            Interlocutor message = gson.fromJson(reader, Interlocutor.class);
            log.debug((++i) +" add new interlocutor");
            interlocutorDeEntities.add(message);
        }
        reader.endArray();
        reader.close();
        return interlocutorDeEntities;
    }

Большое спасибо !


person Mirlo    schedule 01.07.2020    source источник
comment
Если это 40 ГБ JSON, я сомневаюсь, что весь набор данных поместится в вашей памяти. Даже после десериализации в набор объектов.   -  person Benjamin Maurer    schedule 01.07.2020
comment
можете написать свой парсер с помощью JsonParser.nextToken()   -  person Viet    schedule 01.07.2020
comment
baeldung.com/jackson-streaming-api   -  person silentsudo    schedule 01.07.2020
comment
Потоковые API доступны, например: sites.google.com/site/gson/streaming будет удалять строковые данные (json), как только они будут декомпилированы в объекты Java.   -  person Animesh Sahu    schedule 01.07.2020
comment
Зачем он нужен в виде списка объектов?   -  person andreoss    schedule 01.07.2020


Ответы (2)


есть ли способ прочитать этот файл с помощью BufferedReader, а затем нажать объект за объектом?

Конечно, нет. Даже вы можете открыть этот файл, как вы можете хранить 40 ГБ в виде объектов Java в памяти? Я думаю, что у вас нет такого объема памяти на ваших компьютерах (но технически, используя ObjectMapper, у вас примерно в 2 раза больше оперативной памяти - 40 ГБ для хранения json + 40 ГБ для хранения результатов в виде объектов Java = 80 ГБ).

Я думаю, вы должны использовать любые способы из этих вопросов , но хранить информацию в базах данных или файлах, а не в памяти. Например, если у вас есть миллионы строк в json, вы должны анализировать и сохранять каждую строку в базу данных, не сохраняя все это в памяти. И затем вы можете постепенно получать эти данные из базы данных (например, не более 1 ГБ за каждый раз).

person Slava Vedenin    schedule 01.07.2020
comment
Теоретически это возможно, как доказывает SAX (для XML). Конечно, вы не можете держать весь документ в памяти сразу, но вы можете прочитать части структуры, записать их в базу данных/в меньшие документы для отдельных объектов, удалить их из памяти и повторить. Однако я не знаю какой-либо реализации, которая делает это. - person ; 01.07.2020

Вам обязательно следует взглянуть на API потоковой передачи Jackson (https://www.baeldung.com/jackson-streaming-api). Я сам использовал его для больших файлов JSON в ГБ. Самое замечательное, что вы можете разделить свой JSON на несколько небольших объектов JSON, а затем проанализировать их с помощью mapper.readTree(parser). Таким образом, вы сможете совместить удобство обычного Jackson со скоростью и масштабируемостью Streaming API.

Связано с вашей проблемой:

Я понял, что у вас действительно большой массив (что является причиной размера файла) и некоторые гораздо более читаемые объекты:

e.g.:

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

Что вы можете сделать сейчас, так это проанализировать файл с помощью потокового API Джексона и просмотреть массив. Но каждый отдельный объект можно проанализировать как обычный объект Джексона, а затем легко обработать.

Вы можете взглянуть на это Использование Джексона для потокового разбора массив объектов Json, который на самом деле очень хорошо соответствует вашей проблеме.

person Ayk Borstelmann    schedule 01.07.2020
comment
Ваше решение также работает, но мой объект имеет много зависимостей (объект внутри других), поэтому мне нужен один способ чтения и преобразования в объект. Спасибо - person Mirlo; 01.07.2020
comment
Что ж, с этим решением вы также можете прочитать все объекты в наборе. На самом деле это то же самое решение, которое вы нашли, но вместо использования Gson будет использоваться Jackson. - person Ayk Borstelmann; 01.07.2020