Самый быстрый способ импортировать миллионы документов JSON в MongoDB

У меня есть более 10 миллионов документов JSON формы:

["key": "val2", "key1" : "val", "{\"key\":\"val", \"key2\":\"val2"}"]

в одном файле.

Импорт с использованием JAVA Driver API занял около 3 часов, используя следующую функцию (одновременно импортируя один BSON):

public static void importJSONFileToDBUsingJavaDriver(String pathToFile, DB db, String collectionName) {
    // open file
    FileInputStream fstream = null;
    try {
        fstream = new FileInputStream(pathToFile);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        System.out.println("file not exist, exiting");
        return;
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(fstream));

    // read it line by line
    String strLine;
    DBCollection newColl =   db.getCollection(collectionName);
    try {
        while ((strLine = br.readLine()) != null) {
            // convert line by line to BSON
            DBObject bson = (DBObject) JSON.parse(JSONstr);
            // insert BSONs to database
            try {
                newColl.insert(bson);
            }
            catch (MongoException e) {
              // duplicate key
              e.printStackTrace();
            }


        }
        br.close();
    } catch (IOException e) {
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }


}

Есть ли более быстрый способ? Может быть, настройки MongoDB могут влиять на скорость ввода? (например, добавить ключ: "_id", который будет функционировать как индекс, так что MongoDB не будет создавать искусственный ключ и, следовательно, индекс для каждого документа) или вообще отключить создание индекса при вставке. Благодарю.

Ответ 1

Извините, но вы выбрали незначительные проблемы с производительностью вместо основного. Отделять логику от чтения файла и вставки - это небольшой коэффициент усиления. Загрузка файла в двоичном режиме (через MMAP) - небольшое усиление. Использование больших вставных вкладок - большой выигрыш, но до сих пор нет кубиков.

Все узкое место производительности - BSON bson = JSON.parse (линия). Или, другими словами, проблема с драйверами Java заключается в том, что им нужно преобразование из json в bson, и этот код, кажется, ужасно медленный или плохо реализованный. Полный JSON (кодирование + декодирование) через JSON-простой или специально через JSON-smart в 100 раз быстрее, чем команда JSON.parse().

Я знаю, что Qaru говорит мне прямо над этим полем, что я должен отвечать на ответ, а это не так, но будьте уверены, что я все еще ищу ответ на эту проблему. Я не могу поверить в все разговоры о производительности в Монго, и тогда этот простой примерный код терпит неудачу так жалко.

Ответ 2

Я импортировал многострочный json файл с записями ~ 250M. Я просто использую mongoimport <data.txt, и это заняло 10 часов. По сравнению с 10 М против 3 часов я думаю, что это значительно быстрее.

Кроме того, по моему опыту писать свой собственный многопоточный парсер будет резко ускорять работу. Процедура проста:

  1. Откройте файл как BINARY (не ТЕКСТ!)
  2. Установите маркеры (смещения) равномерно по всему файлу. Количество маркеров зависит от количества требуемых потоков.
  3. Найдите "\n" рядом с маркерами, откалибруйте маркеры, чтобы они были выровнены по линиям.
  4. Разбирайте каждый кусок с помощью потока.

Напоминание:

когда вам нужна производительность, не используйте средство чтения потоков или любые встроенные методы чтения на основе строк. Они медленные. Просто используйте двоичный буфер и найдите "\n", чтобы идентифицировать строку, и (наиболее предпочтительно) выполните разбор на месте в буфере без создания строки. В противном случае сборщик мусора не будет так доволен этим.

Ответ 3

Вы можете разобрать весь файл вместе сразу и вставить весь json в документ mongo. Избегайте нескольких циклов. Вам нужно отделить логику следующим образом:

1) Разберите файл и извлеките json Object.

2) После завершения синтаксического анализа сохраните объект json в Mongo Document.

Ответ 4

У меня есть несколько более быстрый способ (я также вставляю миллионы на данный момент), вставлять коллекции вместо отдельных документов с

insert(List<DBObject> list)

http://api.mongodb.org/java/current/com/mongodb/DBCollection.html#insert(java.util.List)

Тем не менее, это не намного быстрее. Я собираюсь поэкспериментировать с настройкой других WriteConcerns, чем ACKNOWLEDGED (главным образом UNACKNOWLEDGED), чтобы узнать, могу ли я ускорить его быстрее. См. Http://docs.mongodb.org/manual/core/write-concern/ для информации

Другим способом повышения производительности является создание индексов после массовой вставки. Однако это редко вариант, за исключением одного рабочего места.

Извиняюсь, если это слегка шерстяное звучание, я все еще сам тестирую. Хороший вопрос.

Ответ 5

Используйте вставку /upserts для массовых операций. После Mongo 2.6 вы можете делать Bulk Updates/Upserts. Пример ниже делает массовое обновление с использованием драйвера c#.

MongoCollection<foo> collection = database.GetCollection<foo>(collectionName);
      var bulk = collection.InitializeUnorderedBulkOperation();
      foreach (FooDoc fooDoc in fooDocsList)
      {
        var update = new UpdateDocument { {fooDoc.ToBsonDocument() } };
        bulk.Find(Query.EQ("_id", fooDoc.Id)).Upsert().UpdateOne(update);
      }
      BulkWriteResult bwr =  bulk.Execute();

Ответ 6

Вы также можете удалить все индексы (за исключением индекса PK, конечно) и перестроить их после импорта.

Ответ 7

Вы можете использовать объемную вставку

Вы можете прочитать документацию на веб-сайте mongo, и вы также можете проверить этот пример java на StackOverflow