Вопрос

Каждый день я получаю запас документов (обновление). То, что я хочу сделать, это вставить каждый предмет, который еще не существует.

  • Я также хочу отследить первый раз, когда я вставил их, и в последний раз я видел их в обновлении.
  • Я не хочу иметь дубликаты документов.
  • Я не хочу удалять документ, который ранее был сохранен, но не в моем обновлении.
  • 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 записей, и у меня миллионы в обновлении). Я почти уверен, что для этого есть что-то встроенное, но документ для обновления () это мммхх .... немного обработано .... (http://www.mongodb.org/display/docs/updating. )

Может кто-нибудь посоветовать, как это сделать быстрее?

Это было полезно?

Решение

Похоже, вы хотите сделать «Упсерт». Mongodb имеет встроенную поддержку для этого. Передайте дополнительный параметр на ваше обновление () Вызов: {upsert: true}. Например:

key = {'key':'value'}
data = {'key2':'value2', 'key3':'value3'};
coll.update(key, data, upsert=True); #In python upsert must be passed as a keyword argument

Это заменяет ваш блок, если-leNe-else-Update полностью. Он будет вставлять, если ключ не будет существовать и будет обновляться, если он будет.

До:

{"key":"value", "key2":"Ohai."}

После:

{"key":"value", "key2":"value2", "key3":"value3"}

Вы также можете указать, какие данные вы хотите написать:

data = {"$set":{"key2":"value2"}}

Теперь ваш выбранный документ обновит значение только «Key2» и оставить все остальное нетронутое.

Другие советы

В качестве MongoDB 2.4 вы можете использовать $ setoninsert (http://docs.mongodb.org/manual/reference/operator/setoninsert/)

Установите «insertion_date», используя $ setoninsert и 'last_update_date', используя $, используя в вашей команде Upsert.

Чтобы включить псевдокод в рабочий пример:

now = datetime.utcnow()
for document in update:
    collection.update_one(
        {"_id": document["_id"]},
        {
            "$setOnInsert": {"insertion_date": now},
            "$set": {"last_update_date": now},
        },
        upsert=True,
    )

Вы всегда можете сделать уникальный индекс, который заставляет MongoDB отклонить противоречивое сохранение. Рассмотрим следующее, сделанное с помощью оболочки MongoDB:

> db.getCollection("test").insert ({a:1, b:2, c:3})
> db.getCollection("test").find()
{ "_id" : ObjectId("50c8e35adde18a44f284e7ac"), "a" : 1, "b" : 2, "c" : 3 }
> db.getCollection("test").ensureIndex ({"a" : 1}, {unique: true})
> db.getCollection("test").insert({a:2, b:12, c:13})      # This works
> db.getCollection("test").insert({a:1, b:12, c:13})      # This fails
E11000 duplicate key error index: foo.test.$a_1  dup key: { : 1.0 }

Вы можете использовать Upsert с $ SetonInsert Operator.

db.Table.update({noExist: true}, {"$setOnInsert": {xxxYourDocumentxxx}}, {upsert: true})

1. Используйте обновление.

Рисунок от ответа Ван Нгуена выше, используйте обновление вместо сохранения. Это дает вам доступ к опции Upsert.

ПРИМЕЧАНИЕ: Этот метод переопределяет весь документ при найденном (От документов)

var conditions = { name: 'borne' }   , update = { $inc: { visits: 1 }} , options = { multi: true };

Model.update(conditions, update, options, callback);

function callback (err, numAffected) {   // numAffected is the number of updated documents })

1.a. Использовать $ Set.

Если вы хотите обновить выбор документа, но не все, что вы можете использовать метод $ Set с обновлением. (опять таки, От документов) ... так, если вы хотите установить ...

var query = { name: 'borne' };  Model.update(query, ***{ name: 'jason borne' }***, options, callback)

Отправьте его как ...

Model.update(query, ***{ $set: { name: 'jason borne' }}***, options, callback)

Это помогает предотвратить случайное перезаписывать все ваши документы с { name: 'jason borne' }.

Я не думаю, что Mongodb поддерживает этот тип селективного восприятия. У меня такая же проблема, как лечиз, а использование Обновление (критерии, Newobj, Upsert, Multi) Не работает прямо при работе с «созданным», так и «обновленным» временем. Учитывая следующее утверждение UPSERT:

update( { "name": "abc" }, 
        { $set: { "created": "2010-07-14 11:11:11", 
                  "updated": "2010-07-14 11:11:11" }},
        true, true ) 

Сценарий № 1 - документ с «именем» «ABC» не существует: новый документ создается с «именем» = «ABC», «создано» = 2010-07-14 11:11:11 и «обновлено» = 2010-07-14 11:11:11.

Сценарий № 2 - Документ с «именем» «abc» уже существует со следующими: «Имя» = «abc», «Создано '= 2010-07-12 09:09:09 и' updated '= 2010-07 -13 10:10:10. После UPSERT документ теперь будет таким же, как результат в сценарии № 1. Нет никаких способов указать в Upsert, поля устанавливаются при вставке, и какие поля остаются в одиночку, если обновление.

Мое решение было созданию уникального индекса на критерия Поля выполняют вставку и сразу после этого выполните обновление просто на «Обновленном» поле.

Резюме

  • У вас есть существующая коллекция записей.
  • У вас есть заданные записи, которые содержат обновления для существующих записей.
  • Некоторые из обновлений действительно ничего не обновляют, они дублируют то, что у вас уже есть.
  • Все обновления содержат одни и те же поля, которые уже есть, просто возможно разные значения.
  • Вы хотите отслеживать, когда запись в последний раз изменена, где значение фактически изменилось.

Примечание, я предполагаю, что Пимонго, измените в соответствии со своим языком выбора.

Инструкции:

  1. Создайте коллекцию с индексом с уникальным = True, так что вы не получаете дубликаты записей.

  2. Итайте для ваших входных записей, создавая партии из них 15 000 записей или около того. Для каждой записи в пакете создайте дикт, состоящий из данных, которые вы хотите вставить, предполагая, что каждый будет новой записью. Добавьте «Созданные» и «Обновленные» метки времени для них. Выдайте это как команда пакетной вставки с флагом «informonError» = True, поэтому вставка всего остального происходит, даже если там есть дубликата там (который звучит так, как будет). Это произойдет очень быстро. Массовые вставки Rock, я получил 15 тысяч / второй уровень производительности. Дальнейшие заметы на inforeronError, см. http://docs.mongodb.org/manual/core/write-oxerations/

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

  3. Итайте для всех ваших входных записей снова, создавая партии 15K или около того. Извлечь ключи (лучше всего, если есть один ключ, но нельзя помочь, если нет). Получите эту кучу записей из Mongo с DB.CollectionNameblah.find ({field: {$ in in: [1, 2,3 ...}). Для каждой из этих записей определите, есть ли обновление, и если это так, выпустите обновление, в том числе обновление «обновленного» метки времени.

    К сожалению, следует отметить, что Mongodb 2.4 и ниже не включают операцию обновления объема. Они работают над этим.

Очки оптимизации ключей:

  • Вставки значительно ускоряют ваши операции навалом.
  • Получение записей RU MASSSE будет ускорить вещи.
  • Индивидуальные обновления - единственный возможный маршрут сейчас, но на нем работает 10gen. Предположительно, это будет в 2.6, хотя я не уверен, что к тому времени будет завершено, есть много вещей (я следовал за их системой JIRA).

В общем, использование обновления лучше в MongoDB, поскольку он просто создаст документ, если оно пока не будет существовать, хотя я не уверен, как работать с вашим адаптером Python.

Во-вторых, если вам нужно только знать, существует ли этот документ, подсчитать (), который возвращает только число, будет лучшим вариантом, чем find_one, который предположительно переносит весь документ с вашего Mongodb, вызывая ненужный трафик.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top