Параллельная загрузка данных в Neo4j
Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті
Просто решил поделиться.
Попался мне проект от заказчика из Дании, наверное, учёного.
У него был 500 Мб файл с 11 млн строк, в котором всего 3 колонки: код протеина 1, код протеина 2 и какое-то число, означавшее связь между ними.
Он хотел загрузить эти данные в графовую базу данных Neo4j, чтобы считать кратчайшие пути по графу.
Проблема была в том, что он пытался загрузить это стандартными средствами, и по моим прикидкам, на это ушло бы 600 часов.
500 Мб данных — как бы немного, но последовательно вставить 11 млн записей означало найти нужные ноды, заблокировать их и создать объект связи между ними. Это сильно тормозит процесс.
Я взялся попробовать.
Сначала я уменьшил имена протеинов: вместо строкового представления типа «9606.ENSP00000000233» (по согласию клиента) было решено использовать только числовую часть, то есть в этом примере просто «233».
Размер файла сильно уменьшился, плюс я рассчитывал на то, что если сделать поле с этим кодом в Neo4j числовым, а не текстовым, то и размер базы и поисковых индексов будет меньше, т.е. быстрее.
Я попробовал загружать этот файл паралелльно в несколько потоков. Работало быстро, но практически ничего не записывало в базу — если мы говорим базе данных «запиши: протеин А связан с протеином В», то оба эти объекта блокируются для записи, и все остальные параллельные попытки связать протеин А с протеинами C, D и E просто идут в никуда — нельзя записывать то, что заблокировано (а ждать Neo4j не хочет).
То есть работало быстро, но неправильно.
Долго возился я с разными вариациями, в итоге пришел к такой идее: эта база данных умеет загружать сразу большой блок данных, например, 1000 строк, но если в этом блоке будут повторяющиеся протеины, то часть данных запишется, а часть пропадёт (из-за описанных выше блокировок).
Идея была в том, чтобы перегруппировать 11 млн записей группами по 1000 строк. Так, чтобы в каждой группе не было повторяющихся протеинов. Тогда все эти 1000 строк могут быть записаны параллельно. Потом берётся следующая группа из 1000 строк.
Перегруппировка шла медленно, так что я оставил скрипт на ночь. Утром попробовал загрузить результат: вместо 600 часов данные загружаются за 8.5 минут.
Когда уже знаешь, «как надо было», то это очевидно, а вот прийти к правильной идее самому — неоценимое удовольствие.
5 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів