8

Mongoシェルで単純なマップreduceを実行しようとしていますが、reduce関数が呼び出されることはありません。これは私のコードです:

db.sellers.mapReduce( 
    function(){ emit( this._id, 'Map') } , 
    function(k,vs){ return 'Reduce' }, 
    { out: { inline: 1}})

そしてその結果は

{
"results" : [
    {
        "_id" : ObjectId("4da0bdb56bd728c276911e1a"),
        "value" : "Map"
    },
    {
        "_id" : ObjectId("4da0df9a6bd728c276911e1b"),
        "value" : "Map"
    }
],
"timeMillis" : 0,
"counts" : {
    "input" : 2,
    "emit" : 2,
    "output" : 2
},
"ok" : 1,

}

どうしたの?

Ubuntu10.10でMongoDB1.8.132ビットを使用しています

4

4 に答える 4

18

の目的reduceは、ekhem、特定のキーに関連付けられた値のセットを 1 つの値に減らすことです (集計結果)。MapReduce キーごとに 1 つの値のみを発行する場合、reduce は必要なく、すべての作業が完了します。しかし、指定された に対して 2 つのペアを発行する_idと、reduce が呼び出されます。

emit(this._id, 'Map1');
emit(this._id, 'Map2');

これは以下のパラメータで reduce を呼び出します:

reduce(_id, ['Map1', 'Map2'])

_idデータセットをフィルタリングするときに MapReduce キーに使用する可能性が高くなりますemit。特定のレコードが何らかの条件を満たしている場合のみです。ただしreduce、この場合も呼び出されません。これは予想どおりです。

于 2011-04-10T12:53:30.000 に答える
6

MongoDB は、値が 1 つしかない場合、キーに対して Reduce 関数を呼び出しません。

私の意見では、これは悪いことです。特異値をスキップするか、何らかの操作を行うかを決定するのは、私のレデューサー コードに任せるべきです。

ここで、特異値に対して何らかの操作を行う必要がある場合、最終的にファイナライズ関数を記述し、ファイナライズで、レデューサーを通過した値とそうでない値を区別しようとします。

Hadoop の場合、このようなことは起こらないと確信しています。

于 2014-07-18T14:20:00.300 に答える
1

また、ドキュメントによると、「MongoDB は、同じキーに対して reduce 関数を複数回呼び出すことができます。この場合、そのキーの reduce 関数からの以前の出力は、への入力値の 1 つになります。次に、そのキーの関数呼び出しを減らします。".

また、reduce結合的、可換的、冪等でなければなりません。

reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] )
reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray )
reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )

したがって、reduce関数は、それ自体の前回の呼び出しの結果であるオブジェクトを受け取る準備ができている必要があることを意味します。これは (少なくとも私にとっては個人的に) 実装する最善の方法mapReduceは、map(可能であれば)reduce関数が返す値と同じ形式で値を発行するようにすることです。次に、reduce1 つの入力形式のみをサポートするように関数を実装できます。その結果、 によって発行されたオブジェクトが 1 つしかない場合でもmap(その結果、 の呼び出しreduceがスキップされた場合)、 の最終結果ではmapReduce、 が呼び出されなかったキーの値reduceが引き続き に残ります。残りのキーの値と同じ形式。

たとえば、次のドキュメント構造があるとします。

{ 
    "foo": <some_string>,
    "status": ("foo"|"bar")
}

map関数は次のようになります。

function() {
    var value = {
       "num_total": 1,
       "num_foos": 0,
       "num_bars": 0
    };

    if (this.status == "foo") {
        value["num_foos"] += 1;
    }

    if (this.status == "bar") {
        value["num_bars"] += 1;
    }

    emit(this.foo, value);
}

reduce関数は次のようになります。

function(key, values) {
    var reduced = {
       "num_total": 0,
       "num_foos": 0,
       "num_bars": 0
    };

    values.forEach(function(val) {
        reduced["num_total"] += val["num_total"];
        reduced["num_foos"] += val["num_foos"];
        reduced["num_bars"] += val["num_bars"];
    });

    return reduced;
}
于 2016-05-23T15:19:58.493 に答える