18


8

mongoDB map / reduceからreduceを引いたもの

最終的なデータコンシューマ( R)にアクセスしやすくするために、いくつかのjavascript操作を実行したいデータの25,000個のドキュメント(生のjsonで4 GB)があります。 "変更ごとに新しいコレクションを追加することでこれらの変更が行われますが、` reduce`なしで map / reduce`を実行する方法がわかりません。 1対1のドキュメントマッピングが必要です。まず、 `collection_1`の25,356個のドキュメントから始め、 collection_2`の25,356個のドキュメントで終わります。

これでハッキングできます:

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

そしてそれを次のように呼びます。

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

(私のマッパーは、文字列を最初の引数として、最後のドキュメントを2番目として1回だけ発行します。 私が本当に欲しいのは、これらの2番目の引数のコレクションです。)

しかし、それは厄介なようで、マッパーの「emit」呼び出し引数は「reducer」の戻り引数と同等ではないため、なぜ機能するのかわかりません。 さらに、次のようなドキュメントになります

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

不要なようです。

また、独自の挿入を実行するカーソルは、「mapReduce」ほど高速ではありません。 私はそれをベンチマークするのに十分なほどMongoDBを知りませんが、「50x」ほど遅いと思います。 カーソルを並行して実行する方法はありますか? collection_2`のドキュメントが collection_1`のドキュメントと異なる順序であるかどうかは気にしません。

5 Answer


6


map / reduceを使用すると、常に次のようになります。

{ "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


_ しかし、それは厄介なようで、マッパーの「emit」呼び出し引数は「reducer」の戻り引数と同等ではないため、なぜ機能するのかわかりません。 _

それらは同等です。 reduce関数は T`値の配列を受け取り、同じ T`形式で単一の値を返す必要があります。 「T」の形式は、マップ関数によって定義されます。 reduce関数は、値配列の最初の項目を返すだけで、常に `T`型になります。 それが動作する理由です:)

あなたは正しい軌道に乗っているようです。 私はいくつかの実験を行い、マップ関数から `db.collection.save()`を実行できないようですが、reduce関数から実行できます。 マップ関数は、必要なドキュメント形式を単純に構築する必要があります。

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

マップ関数は、元のドキュメントのIDを再利用します。 同じキーを共有する値はないため、これにより再縮小ステップが防止されます。

reduce関数は単純に「null」を返すことができます。 ただし、さらに、*値を別のコレクション*に書き込むことができます。

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

  return null;
}

これで、 `db.result`には、一時的なコレクションにある追加のmap-reduceノイズなしで、変換されたドキュメントが含まれるはずです。 大量のデータで実際にこれをテストしたことはありませんが、このアプローチではmap-reduce関数の並列実行を活用する必要があります。


1


mongoシェルにアクセスすると、いくつかのJavascriptコマンドが受け入れられ、より簡単になります。

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

db.collection.find().forEach(map);


0


縮小なしのマップのみがコレクションのコピーに似ています:http://www.mongodb.org/display/DOCS/Developer+FAQ#DeveloperFAQ-HowdoIcopyallobjectsfromonedatabasecollectiontoanother%3F


0


私は同じ状況に直面しました。 Mongoクエリとプロジェクションを介してこれを達成できました。 Mongo Queryを参照してください