Самый быстрый способ импортировать миллионы документов 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 часов я думаю, что это значительно быстрее.
Кроме того, по моему опыту писать свой собственный многопоточный парсер будет резко ускорять работу. Процедура проста:
- Откройте файл как BINARY (не ТЕКСТ!)
- Установите маркеры (смещения) равномерно по всему файлу. Количество маркеров зависит от количества требуемых потоков.
- Найдите "\n" рядом с маркерами, откалибруйте маркеры, чтобы они были выровнены по линиям.
- Разбирайте каждый кусок с помощью потока.
Напоминание:
когда вам нужна производительность, не используйте средство чтения потоков или любые встроенные методы чтения на основе строк. Они медленные. Просто используйте двоичный буфер и найдите "\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