0

php で mongo による map reduce 関数が必要です

この私のmongo構造

[_id] => MongoId Object (
    [$id] => 4fcf2f2313cfcd2454500000d
)
[id] => 454
[table] => people
[news] => Array (
    [03-06-2012] => 2
    [04-06-2012] => 3
    [05-06-2012] => 5
    [06-06-2012] => 4
)

ここでは、以下のコードで配列ニュースを合計しようとしています。

    $map = new MongoCode('function() { emit(this.news, 1); }');
    $reduce = new MongoCode('function(previous, current) {
                    var count = 0;
                    for (index in current) {
                        count = count + current[index];
                    }
                    return count;
                }');

    $sales = $db->command(array(
        'mapreduce' => 'mycollection',
        'map' => $map,
        'reduce' => $reduce,
        'query' => array('table' => 'people'),
        'out'  => 'news'
    ));

    //pr($sales);exit;

    $users = $db->selectCollection($sales['result'])->find();

    foreach ($users as $user) {
        //echo "{$user['_id']} had {$user['value']} sale(s).\n";
        pr($user);
    }

いつpr($user)

Array
(
    [_id] => Array
    (
        [04-06-2012] => 0
        [08-06-2012] => 2
        [11-06-2012] => 6
    )

    [value] => 39540
)

値が 39540 ではなく 8 になると予想していました。

この関数を修正するにはどうすればよいですか?また、元のコレクション(mycollection)に「ニュース」の配列合計としてフィールド合計を追加する方法は?

私はmongoのmap reduce関数に慣れていません。

4

2 に答える 2

3

を呼び出すときemit()、最初のパラメーターは削減する (この例ではグループ化する) キーです。2 番目のパラメーターは、そのキーに対して出力される値であり、何でもかまいません。あなたの例ではnews、ドキュメントの ID をキーとして使用して、フィールド内のすべての値の合計を発行することを意味している可能性があります。

var map = function() {
    var total = 0;
    for (count in this.news) {
        total += count;
    }
    emit(this._id, total);
}

この場合、プレースホルダーの reduce 関数を使用できます (発行された各キーは一意であるため、実行する削減はほとんどありません)。

var reduce = function(key, values) {
    var total = 0;
    values.forEach(function(v) { total += v; });
    return total;
}

ただし、Google グループの投稿で述べたように、純粋な PHP でこれを行う方がよい場合があります。

$cursor = $collection->find(array(), array('news' => 1));
$cursor->snapshot();

foreach ($cursor as $document) {
    $collection->update(
        array('_id' => $document['_id']),
        array('$set' => array('sum' => array_sum($document['news']))),
        array('multiple' => false)
    );
}

map/reduce では、その結果を調べてレコードを更新する必要があります。これにより、Mongo を介して JavaScript を実行する必要がなくなり、パフォーマンスが向上します。newsまた、ドキュメントごとにフィールドが変更されたときに $inc を使用して合計を更新できれば、さらに効果的です。sum上記のスニペットは、コレクション全体のフィールドを初期化したり、ドキュメントごとの増分で同期が取れなくなった場合にドリフトを修正したりするのに引き続き役立ちます。

注:上記の例でのメソッド呼び出しの背後にある理由については、ドキュメントのsnapshot()を参照してください。

于 2012-06-12T23:45:50.583 に答える
1

jmikolaの答えは、mongo map reduce関数に対処するためのライトトラックを私に与えてくれます。

将来の訪問者を支援するために、この回答を追加しています。

次のmap-reduce関数は、私の要件に完全に対応しています。これにより、news フィールドのすべての値が、news( ) を追加してコマンドで作成されたという新しいコレクションに合計され"out" => "news"ます。

マップリデュース機能

$map = new MongoCode('function() {
            var total = 0;
            for (count in this.news) {
            total +=  this.news[count];
            }
            emit(this._id, {id: this.id, total: total});
        }');
$reduce = new MongoCode('function(key, values) {
            var result = {id: null, total: 0};
            values.forEach(function(v) {
            result.id = v.id;
            result.total = v.total;
             });
            return result;
        }');

$sales = $db->command(array(
    'mapreduce' => 'mycollection', // collection name
    'map' => $map,
    'reduce' => $reduce,
    'query' => array('table' => 'people'),
    "out" => "news" // new collection name
));

結果は、実際のドキュメントのnews合計としてコレクションになりますtotalid

出力

[_id] => MongoId Object (
    [$id] => 4fd8993a13cfcd4e42000000
)
[value] => Array (
    [id] => 454
    [total] => 14
)
于 2012-10-10T11:03:54.970 に答える