Каждый день я получаю запас документов (обновление). Что я хочу сделать, это вставить каждый элемент, который еще не существует.
- Я также хочу отслеживать первый раз, когда я их вставил, и последний раз, когда я видел их в обновлении.
- Я не хочу иметь дубликаты документов.
- Я не хочу удалять документ, который был ранее сохранен, но отсутствует в моем обновлении.
- 95% (по оценкам) записей не изменены со дня на день.
Я использую драйвер Python (pymongo).
В настоящее время я делаю (псевдокод):
for each document in update:
existing_document = collection.find_one(document)
if not existing_document:
document['insertion_date'] = now
else:
document = existing_document
document['last_update_date'] = now
my_collection.save(document)
Моя проблема в том, что это очень медленно (40 минут для менее чем 100 000 записей, и у меня их миллионы в обновлении). Я почти уверен, что для этого есть что-то встроенное, но документ для update () - это ммммххх ... немного кратко .... ( http://www.mongodb.org/display/DOCS/Updating )
Может кто-нибудь посоветовать, как это сделать быстрее?
Начиная с MongoDB 2.4, вы можете использовать $ setOnInsert ( http://docs.mongodb.org/manual/reference/operator/setOnInsert/ )
Установите 'inserttion_date', используя $ setOnInsert и 'last_update_date', используя $ set в вашей команде upsert.
Чтобы превратить ваш псевдокод в рабочий пример:
источник
Вы всегда можете создать уникальный индекс, который заставит MongoDB отклонить конфликтующее сохранение. Рассмотрим следующее с использованием оболочки mongodb:
источник
Вы можете использовать Upsert с оператором $ setOnInsert.
источник
1. Используйте Обновление.
Опираясь на ответ Ван Нгуена выше, используйте обновление вместо сохранения. Это дает вам доступ к опции upsert.
ПРИМЕЧАНИЕ . Этот метод переопределяет весь документ при его обнаружении ( из документов ).
1.a. Использовать $ set
Если вы хотите обновить выделенный фрагмент документа, но не все, вы можете использовать метод $ set с update. (опять же из документов ) ... Итак, если вы хотите установить ...
Отправить как ...
Это помогает предотвратить случайную перезапись всех ваших документов
{ name: 'jason borne' }
.источник
Резюме
Обратите внимание, я предполагаю, что PyMongo, изменить в соответствии с вашим языком выбора.
Инструкции:
Создайте коллекцию с индексом unique = true, чтобы вы не получали дубликаты записей.
Перебирайте входные записи, создавая их из 15 000 записей или около того. Для каждой записи в пакете создайте dict, состоящий из данных, которые вы хотите вставить, предполагая, что каждая будет новой записью. Добавьте к ним «созданные» и «обновленные» временные метки. Выполните это как команду пакетной вставки с флагом 'ContinueOnError' = true, чтобы вставка всего остального происходила, даже если там есть дубликат ключа (который, как кажется, будет). ЭТО ПРОИЗОЙДЕТ ОЧЕНЬ БЫСТРО. Массовая вставка рок, я получил 15k / секунду уровней производительности. Дополнительные примечания по ContinueOnError см. По адресу http://docs.mongodb.org/manual/core/write-operations/.
Вставка записей происходит ОЧЕНЬ быстро, так что с этими вставками вы быстро закончите. Теперь пришло время обновить соответствующие записи. Делайте это с пакетным извлечением, намного быстрее, чем по одному за раз.
Повторяйте все входные записи снова, создавая пакеты по 15 КБ или около того. Извлеките ключи (лучше всего, если есть один ключ, но ничего не поделаешь, если его нет). Получите этот набор записей из Mongo с помощью запроса db.collectionNameBlah.find ({field: {$ in: [1, 2,3 ...}). Для каждой из этих записей определите, есть ли обновление, и если да, выпустите обновление, включая обновление «обновленной» временной метки.
К сожалению, мы должны отметить, что MongoDB 2.4 и ниже НЕ включает в себя операцию массового обновления. Они работают над этим.
Ключевые точки оптимизации:
источник
Я не думаю, что mongodb поддерживает этот тип избирательного апсайтинга. У меня та же проблема, что и у LeMiz, и использование update (критериев, newObj, upsert, multi) не работает правильно при работе с «созданной» и «обновленной» временной меткой. Учитывая следующее утверждение upsert:
Сценарий № 1 - документ с «именем» из «abc» не существует: новый документ создан с «name» = «abc», «create» = 2010-07-14 11:11:11 и «updated» = 2010-07-14 11:11:11.
Сценарий № 2 - документ с «именем» из «abc» уже существует со следующим: «имя» = «abc», «создан» = 2010-07-12 09:09:09 и «обновлен» = 2010-07 -13 10:10:10. После упреждения документ теперь будет таким же, как результат в сценарии № 1. В upsert нет способа указать, какие поля будут установлены при вставке и какие поля будут оставлены в одиночку при обновлении.
Моим решением было создать уникальный индекс для полей critera , выполнить вставку и сразу после этого выполнить обновление только для поля «updated».
источник
В общем, использовать обновление лучше в MongoDB, так как оно просто создаст документ, если он еще не существует, хотя я не уверен, как работать с вашим адаптером python.
Во-вторых, если вам нужно только знать, существует ли этот документ, то count (), который возвращает только число, будет лучшим вариантом, чем find_one, который предположительно передает весь документ из вашей MongoDB, вызывая ненужный трафик.
источник