Обновление: Если вы прочитали это, чтобы улучшить скорость вставки / обновления, проверьте, включены ли в вашей системе расширения pymongo C, запустив сначала pymongo.has_c()
из консоли python.Если он разрешается до False
, вам нужно либо скомпилировать pymongo с расширениями C, либо выполнить pip install --upgrade pymongo
. Это улучшило мой рабочий процесс с 17 секунд в строках 10K до примерно 0,57 секунд.
У меня есть тысячи текстовых файлов, содержащих миллионы строк данных, которые я пытаюсь импортировать в коллекцию mongodb.
В настоящее время я использую следующее def :
import re, pymongo
coll = pymongo.MongoClient().database.collection
rx = re.compile(r'[:; ]')
rx_email = re.compile(r'\S+@\S+\.\S+$')
def parser(path):
with open(path, "rb") as f:
for line in f:
try:
fields = rx.split(line.decode('utf-8'))
email = ''
username = ''
for field in fields:
if rx_email.match(field):
email = field
elif field != fields[-1]:
username = field
password = fields[-1]
if email:
coll.find_one_and_update({'email': email}, {'$addToSet': {'passwords': password}}, upsert=True)
elif username:
coll.find_one_and_update({'username': username}, {'$addToSet': {'passwords': password}}, upsert=True)
else:
pass
except UnicodeDecodeError:
pass
if __name__ == "__main__":
parser('path/to/file.txt')
Когда я пытаюсь запустить скрипт для файла с 10K строк, это заняло 74,58974479999999 секунд.Я предполагаю, что это связано с количеством элементов, с которыми MongoDB должен соответствовать, когда я вставляю?Выполнение того же цикла без взаимодействия с БД заняло 0,022998 секунд.
EDIT : как указано в Fast or Bulk Upsert в pymongo , я также пытался использовать UpdateOne
с bulk_write
следующим образом:
def parser(path):
ops = []
with open(path, "rb") as f:
for line in f:
if (len(ops) == 1000):
LOCAL_DB.bulk_write(ops, ordered=False)
ops = []
try:
fields = rx.split(line.decode('utf-8'))
email = ''
username = ''
for field in fields:
if rx_email.match(field):
email = field
elif field != fields[-1]:
username = field
password = fields[-1]
if email:
pass
ops.append((UpdateOne({'identifier': email}, {'$addToSet': {'passwords': password}}, upsert=True)))
elif username:
pass
ops.append((UpdateOne({'identifier': username}, {'$addToSet': {'passwords': password}}, upsert=True)))
else:
pass
except UnicodeDecodeError:
pass
Время завершения 10К строк составляет 17 секунд, что, однако, является способом замедления для количества файлов и строк, которые я пытаюсь обновить.
Есть ли лучшие (и, надеюсь, более быстрые) способы сделать это?
Некоторые требования:
- адрес электронной почты и / или имя пользователя должны быть уникальными.
- Массив, содержащийпароли должны указывать каждый пароль только один раз (также уникальный).
- 1M строк должно (если возможно) занять менее 1 минуты для вставки.