0

map reduce を使用してデータセットをピボットするのに問題があります。MongoDB のクックブックを参考にしていますが、奇妙なエラーが発生します。以下のコレクションをピボットして、各ユーザーがすべてのレビュー評価のリストを取得できるようにします。

私のコレクションは次のようになります。

{
  'type': 'review',
  'business_id': (encrypted business id),
  'user_id': (encrypted user id),
  'stars': (star rating),
  'text': (review text),
}

Map 関数 (Python でラップ):

map = Code(""""
function(){
key = {user : this.user_id};
value = {ratings: [this.business_id, this.stars]};

emit(key, value);
}
""")

map 関数は、キーに関連付けられた値の配列を返す必要があります... Reduce 関数 (Python でラップ):

reduce = Code("""
function(key, values){
var result = { value: [] };
temp = [];

for (var i = 0; i < values.length; i++){
temp.push(values[i].ratings);
}
result.value = temp;
return result;
}
""")

ただし、結果は合計よりも1 つ少ない評価を返します。実際、None が返されるユーザーもいますが、これはあり得ません。一部のエントリは次のようになります。

{u'_id': {u'user: u'zwZytzNIayFoQVEG8Xcvxw'}, u'value': [None, [u'e9nN4XxjdHj4qtKCOPQ_vg', 3.0], None, [...]...]

コードの何が原因であるかを特定できません。レビューが 3 件ある場合、すべてのレビューにビジネス ID と評価がドキュメントに含まれています。さらに、ループ条件で 'values.length + 1' を使用すると、何らかの理由で values[i] が壊れます。

編集 1

reduce はそれ自体で複数回呼び出されるという事実を受け入れたので、以下に新しい reducer を示します。これは、[ビジネス、評価、ビジネス、評価] の配列を返します。1 つの巨大な配列の代わりに [ビジネス、評価] 配列を出力する方法はありますか?

function(key, value){
var result = { ratings:[] };
var temp = [];
values.forEach(function(value){
    value.ratings.forEach(function(rating){
        if(temp.indexof(rating) == -1){
            temp.push(rating);
        }
    });
});

result. rartings = temp;
return result;
}
4

1 に答える 1

1

テスト例を次に示します。

1) いくつかのサンプル データを追加します。

db.test.drop();
db.test.insert(
  [{
    'type': 'review',
    'business_id': 1,
    'user_id': 1,
    'stars': 1,
  },
  {
    'type': 'review',
    'business_id': 2,
    'user_id': 1,
    'stars': 2,
  },
  {
    'type': 'review',
    'business_id': 2,
    'user_id': 2,
    'stars': 3,
  }]
);

2) 地図機能

var map = function() {
  emit(this.user_id, [[this.business_id, this.stars]]);
};

ここでは、プロセスの最後に表示されるように結果を設定します。なんで?ユーザーによるレビューが 1 つしかない場合 (グループ化のキー)、結果は削減フェーズを通過しないためです。

3) リデュース機能

var reduce = function(key, values) {
  var result = { ratings: [] };
  values.forEach(function(value){
    result.ratings.push(value[0]);
  });

  return result;
};

ここでは、すべての値を収集します。マップ メソッドでネストしたことを思い出してください。したがって、結果の各セットの最初の値を選択することができます。

4) map reduce を実行します。

db.test.mapReduce(map, reduce, {finalize: final, out: { inline: 1 }});

別の方法 -集計フレームワークを使用します。

db.test.aggregate({
  $group: {
    _id: "$user_id", 
    ratings: {$addToSet: {business_id: "$business_id", stars: "$stars"}}
  }
});
于 2013-08-19T12:32:44.237 に答える