MongoDB MapReduce обновление на месте, как - PullRequest
6 голосов
/ 16 августа 2011

* Обычно я пытаюсь упорядочить объекты по их количеству за последний час.

Я пытаюсь сгенерировать почасовую сумму голосов для объектов в моей базе данных. Голоса встроены в каждый объект. Схема объекта выглядит следующим образом:

{
    _id: ObjectId
    score: int
    hourly-score: int <- need to update this value so I can order by it
    recently-voted: boolean
    votes: {
        "4e4634821dff6f103c040000": { <- Key is __toString of voter ObjectId
            "_id": ObjectId("4e4634821dff6f103c040000"), <- Voter ObjectId
            "a": 1, <- Vote amount
            "ca": ISODate("2011-08-16T00:01:34.975Z"), <- Created at MongoDate
            "ts": 1313452894 <- Created at timestamp
        },
        ... repeat ...
    }
}

Этот вопрос фактически связан с вопросом, который я задал пару дней назад Лучший способ смоделировать систему голосования в MongoDB

Как мне (можно?) Запустить команду MapReduce для выполнения следующих действий:

  1. Запускать только на объектах с недавно проголосованным = true ИЛИ почасовым счетом> 0.
  2. Рассчитать сумму голосов, созданных за последний час.
  3. Обновление почасовой оценки = сумма, рассчитанная выше, и недавно проголосовавших = ложь.

Я также прочитал здесь , что я могу выполнить MapReduce на подчиненной БД, выполнив db.getMongo (). SetSlaveOk () перед командой M / R. Могу ли я запустить уменьшение на ведомом устройстве и обновить основную БД?

Возможны ли обновления на месте с Mongo MapReduce?

1 Ответ

10 голосов
/ 16 августа 2011

Вы определенно можете сделать это. Я отвечу на ваши вопросы по одному:

1. Вы можете указать запрос вместе со своей картой-редукции, которая фильтрует набор объектов, которые будут переданы в фазу карты. В оболочке mongo это будет выглядеть так (при условии, что m и r являются именами функций вашего картографа и редуктора соответственно):

> db.coll.mapReduce(m, r, {query: {$or: [{"recently-voted": true}, {"hourly-score": {$gt: 0}}]}})

2. Шаг # 1 позволит вам использовать свой картограф для всех документов с хотя бы одним голосом за последний час (или если для recently-voted установлено значение true), но не все голоса были за последний час. Таким образом, вам нужно отфильтровать список в вашем картографическом списке и выдавать только те голоса, которые вы хотите подсчитать:

function m() {
  var hour_ago = new Date() - 3600000;
  this.votes.forEach(function (vote) {
    if (vote.ts > hour_ago) {
      emit(/* your key */, this.vote.a);
    }
  });
}

И уменьшить:

function r(key, values) {
  var sum = 0;
  values.forEach(function(value) { sum += value; });
  return sum;
}

3. Чтобы обновить таблицу почасовых оценок, вы можете использовать опцию reduceOutput для отображения-уменьшения, которая вызовет ваш редуктор как с выданными значениями, так и с ранее сохраненным значением в выходной коллекции (если есть). Результат этого прохода будет сохранен в выходной коллекции. Это выглядит так:

> db.coll.mapReduce(m, r, {query: ..., out: {reduce: "output_coll"}})

В дополнение к повторному сокращению вывода вы можете использовать merge, который будет перезаписывать документы в выходной коллекции на вновь созданные (но оставляя после себя любые документы с _id, отличным от _id, созданных вашим mr job), replace, которая по сути является операцией удаления и создания и используется по умолчанию, или используйте {inline: 1}, которая будет возвращать результаты непосредственно в оболочку или в ваш драйвер. Обратите внимание, что при использовании {inline: 1} ваши результаты должны соответствовать размеру, разрешенному для одного документа (16 МБ в последних выпусках MongoDB).

(4). Вы можете запускать задания уменьшения карты на вторичных серверах («ведомых»), но поскольку вторичные серверы не могут принимать записи (именно это делает их вторичными), это можно сделать только при использовании встроенного вывода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...