1

私はMongoDBのmapReduceを使用して、友人ネットワークからユーザーのトレンド曲を生成しています。そのため、すべてのユーザーを繰り返し処理し、user_idが友達の配列に存在するかどうかを確認します。存在する場合は、ユーザーの曲を放出してから、放出された曲全体をマージして、すべての友達ネットワークの上位の曲を見つけます。

問題は、コレクション内のすべてのユーザーの(ネットワークトレンド曲)を見つけるために、すべてのユーザーを反復処理する必要があることです。どうすればこれを達成できますか、ネストされたmapReduceのような方法はありますか?または、forループを介してmapReduceを実行するように、アプリケーション層から反復する必要がありますか?

私が使用している現在のmapReduceはこれです:

var map = function() {
users = [];
songs = [];
    if(this.value.friends !== undefined && this.value.friends.length !== 0 && this.value.songs !== undefined && this.value.songs.length !== 0){
        key = this._id.user_id;
        for(var x=0; x<this.value.songs.length; x++)
            emit({user_id:user_id,song_id:this.value.songs[x][0]},{played:this.value.songs[x][1], counter:1});
    }
};
var reduce = function(key, values) {
    var counter = 0;
    var played = 0;
    values.forEach(function(val){
        counter += val.counter;
        played += val.played;
    });
    return {played : played, counter : counter};
};
db.runCommand({"mapreduce":"trending_users", "map":map, "reduce":reduce, "scope":{user_id: "111222333444"} ,"query":{'value.friends':{$in : ['111222333444'] }},'out':{merge:'trending_user_network'}})    
db.trending_user_network.find({'_id.user_id':'111222333444'}).sort({'value.counter':-1, 'value.played':-1})
4

1 に答える 1

0

確かに、アプリケーションでforループを使用して、ユーザーIDを循環させ、各IDに対してマップリデュースを実行することができます。ただし、このような場合は、集計フレームワークを使用して集計操作のパイプラインを作成し、すべてを一度に実行する方がよい場合があります。

スキーマの正確な詳細はわかりませんが、次のように集計パイプラインを構築できると思います。

  • $unwind友達のユーザーIDにマップされたユーザーのフラットリストを取得するには
  • $unwindもう一度、友達のユーザーIDを曲のリストにマッピングします
  • $group結果のリスト内の各曲の集計を取得します
  • $sort結果の物を整理する

実際には、パイプラインにはさらにいくつかの手順が必要になる場合がありますが、この問題をmap-reduceではなく集約の観点から見ると、より簡単になると思います。

于 2012-09-28T16:11:48.267 に答える