Решение для Bulk FindAndModify в MongoDB - программирование
Подтвердить что ты не робот

Решение для Bulk FindAndModify в MongoDB

Мой вариант использования выглядит следующим образом: У меня есть сборник документов в mongoDB, который я должен отправить для анализа. Формат документов выглядит следующим образом:

{_id: ObjectId ( "517e769164702dacea7c40d8" ), дата: "1359911127494", Статус: "доступен", other_fields...}

У меня есть процесс чтения, который выбирает первые 100 документов со статусом: доступно отсортировано по дате и изменяет их со статусом: обработка. ReaderProcess отправляет документы для анализа. После завершения анализа состояние будет изменено на обработанное.

В настоящее время процесс чтения сначала выбирает 100 документов, отсортированных по дате, а затем обновляет статус для обработки для каждого документа в цикле. Есть ли лучшее/эффективное решение для этого случая?

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

Массовая findAndModify (с лимитом) решила бы все эти проблемы. Но, к сожалению, он еще не представлен в MongoDB. Есть ли решение этой проблемы?

4b9b3361

Ответ 1

Как вы говорите, в настоящее время нет чистого способа делать то, что вы хотите. Лучший подход в это время для таких операций, как тот, который вам нужен:

  • Reader выбирает документы X с соответствующим лимитом и сортировкой
  • Считыватель отмечает документы, возвращенные 1) с его собственным уникальным идентификатором считывателя (e.g. update({_id:{$in:[<result set ids>]}, state:"available", $isolated:1}, {$set:{readerId:<your reader ID>, state:"processing"}}, false, true))
  • Reader выбирает все документы, помеченные как обработка, и с ним собственный идентификатор считывателя. На этом этапе гарантируется, что у вас есть эксклюзивный доступ к результирующему набору документов.
  • Предложите набор результатов из 3) для вашей обработки.

Обратите внимание, что это даже работает в ситуациях с высокой степенью параллелизма, поскольку читатель никогда не может резервировать документы, которые еще не зарезервированы другим читателем (обратите внимание, что шаг 2 может хранить только доступные в настоящее время документы, а записи - атомарные). Я бы добавил временную метку с временем резервирования, если вы хотите иметь возможность зарезервировать время (например, для сценариев, где читатели могут сбой/сбой).

EDIT: Подробнее:

Все операции записи могут иногда выдаваться для ожидающих операций, если запись занимает относительно большое время. Это означает, что шаг 2) может не увидеть все документы, отмеченные на шаге 1), если вы не выполните следующие шаги:

  • Используйте соответствующее значение "w" (запись), значение 1 или выше. Это гарантирует, что соединение, на которое вызывается операция записи, будет ожидать завершения, независимо от того, что оно дает.
  • Убедитесь, что вы прочитали на шаге 2 в том же соединении (только релевантно для репликатов с чтениями с поддержкой slaveOk) или потоком, чтобы гарантировать, что они будут последовательно. Первое может быть сделано в большинстве драйверов с помощью методов "requestStart" и "requestDone" или аналогичных (документация по Java здесь).
    • Добавьте к вашим мульти-обновлениям флаг $изолированных, чтобы он не мог чередоваться с другими операциями записи.

Также см. комментарии для обсуждения атомарности/изоляции. Я неправильно предполагал, что множественные обновления были изолированы. Они не являются или, по крайней мере, не по умолчанию.