карта mongoDB / уменьшить минус уменьшить - PullRequest
18 голосов
/ 27 августа 2010

У меня есть около 25 тыс. Документов (4 ГБ в формате json) данных, над которыми я хочу выполнить несколько операций javascript, чтобы сделать их более доступными для моего конечного потребителя данных (R), и я хотел бы отсортировать«контроль версий» этих изменений, добавляя новую коллекцию для каждого изменения, но я не могу понять, как map/reduce без reduce.Я хочу сопоставление документов «один к одному» - я начинаю с 25 356 документов в collection_1 и хочу получить 25 356 документов в collection_2.

Я могу взломать его с помощью этого:

var reducer = function(key, value_array) {
    return {key: value_array[0]}
}

И затем назовите его так:

db.flat_1.mapReduce(mapper, reducer, {keeptemp: true, out: 'flat_2'})

(Мой маппер вызывает только вызовы emit, со строкой в ​​качестве первого аргумента и окончательным документом в качестве второго. Это наборте вторые аргументы, которые мне действительно нужны.)

Но это кажется неловким, и я не знаю, почему это даже работает, поскольку мои emit аргументы вызова в моем преобразователе не эквивалентны возвращаемому аргументу моего reducer.Кроме того, я получаю документ типа

{
    "_id": "0xWH4T3V3R", 
    "value": {
        "key": {
            "finally": ["here"],
            "thisIsWhatIWanted": ["Yes!"]
        }
    }
}

, который кажется ненужным.

Кроме того, курсор, который выполняет свои собственные вставки, даже не на десятую часть быстрее mapReduce.Я не знаю MongoDB достаточно хорошо, чтобы тестировать его, но я думаю, он примерно на 1024 * медленнее.Есть ли способ параллельно запустить курсор?Мне все равно, если документы в моем collection_2 находятся в другом порядке, чем документы в collection_1.

Ответы [ 5 ]

6 голосов
/ 31 августа 2010

При использовании карты / уменьшения вы всегда получите

{ "value" : { <reduced data> } }

Чтобы удалить клавишу value, вам нужно будет использовать функцию finalize.

Вот самое простое, что вы можете сделать, чтобы скопировать данные из одной коллекции в другую:

map = function() { emit(this._id, this ); }
reduce = function(key, values) { return values[0]; }
finalize = function(key, value) { db.collection_2.insert(value); }

Тогда, когда вы будете работать как обычно:

db.collection_1.mapReduce(map, reduce, { finalize: finalize });
3 голосов
/ 27 августа 2010

Но это кажется неловким, и я не знаю, почему это даже работает, поскольку мои emit аргументы вызова в моем преобразователе не эквивалентны возвращаемому аргументу моего reducer.

Они эквивалентны.Функция Reduce принимает массив значений T и возвращает одно значение в том же формате T.Формат T определяется вашей функцией карты.Ваша функция Reduce просто возвращает первый элемент в массиве значений, который всегда будет иметь тип T.Вот почему это работает:)

Вы, кажется, на правильном пути.Я провел некоторые эксперименты, и кажется, что вы не можете сделать db.collection.save() с помощью функции карты, но вы можете сделать это с помощью функции уменьшения.Ваша функция карты должна просто создать необходимый вам формат документа:

function map() {
  emit(this._id, { _id: this.id, heading: this.title, body: this.content });
}

Функция карты использует идентификатор исходного документа.Это должно предотвратить любые шаги повторного сокращения, поскольку никакие значения не будут использовать один и тот же ключ.

Функция уменьшения может просто вернуть null.Но кроме того, вы можете записать значение в отдельную коллекцию .

function reduce(key, values) {
  db.result.save(values[0]);

  return null;
}

Теперь db.result должен содержать преобразованные документы, без какого-либо дополнительного шума, уменьшающего карту, который вы бы имеливо временной коллекции.На самом деле я не проверял это на больших объемах данных, но этот подход должен использовать преимущества параллельного выполнения функций преобразования карты.

1 голос
/ 17 апреля 2016

Когда вы получили доступ к оболочке mongo, она принимает некоторые команды Javascript, а затем становится проще:

map = function(item){
        db.result.insert(item);
}

db.collection.find().forEach(map);
0 голосов
/ 17 мая 2014

Я столкнулся с такой же ситуацией. Я смог сделать это с помощью запроса и проекции Монго. см. Монго Запрос

0 голосов
/ 27 августа 2010

Только карта без уменьшения аналогична копированию коллекции: http://www.mongodb.org/display/DOCS/Developer+FAQ#DeveloperFAQ-HowdoIcopyallobjectsfromonedatabasecollectiontoanother%3F

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