このブログを検索

2013/02/15

MongoDBのMapreduceの落とし穴(undefinedが発生する理由と対策)

1)Mapreduceで集計をしたらreduceの処理途中にundefineのレコードがあり、一部集計が失敗した。

不良データを探そうとprint()で_idで調べたら以下のような結果となり不良データがないように見えた。
Map/reduce : _id
map : 1
map : 2
map : 3
reduce : 1
reduce : 2
reduce : 3
map : 4
map : 5
reduce : undefine
reduce : 4
reduce : 5

原因と対策方法は時間があるときに探そう。

2つのCollectionを纏めてMapreduce方法を探していたら
http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/
 if (this.FY2009 !== undefined && this.FY2009 !== null) {
 のようなCodeがあった。

2)上は解決したが、それでも集計結果が不一致。
以下の_id : 3 が集計されない。reduceの実行のタイミング怪しい?

Map/reduce :_id : group key(break key?)
map : 1 : 2013-01-01
map : 2 : 2013-01-01
map : 3 : 2013-01-02
reduce : 1  : 2013-01-01
reduce : 2 : 2013-01-01
reduce : 3 : 2013-01-02
map : 4 : 2013-01-02
map : 5 : 2013-01-03
reduce : undefined : undefined ← reduce : 3までの処理結果
reduce : 4 : 2013-01-02
reduce : 5 : 2013-01-03

原因:map -> reduce→map -> reduceが繰り返し処理される。
この繰り返しの時、前のreduceの結果を引き継ぐためにreduceのValue[0]に前回の処理結果が渡される。

例えば
emit( key: {user_id : [this.user_id], count:1}
reduce(key,v) { var reducedValue = {u_id:[], t_c:0}; ... }
にしたとき
同じkeyの中で2回目に呼ばれたv[0]はreducedValueのu_idとt_cの配列が来る。

http://ryooo321.blogspot.jp/2012/05/mongodbmapreduce.html からヒントを頂きました。

*2013/02/19追記
6576件のデータを集計してみたが
600件ずつ集めて、Groupkeyが変更される前の時点で
600件の配列を10回、576件の配列が1回繰り返しの処理に入って来た。

{Key: 2013-02-17 、件数: 201件}
{Key: 2013-02-18 、件数: 6576件}

reduce -> 2013-02-17 :(100件 X 2回)+1件呼出す
reduce -> 2013-02-18 :(100件 X 6回) X10回+(100件 X 5回)+76件 呼出す
finalize -> 2013-02-17 :1回 呼出す
reduce -> 2013-02-18 : (600件 X10回)+ (576件X1回) 呼出す // 新しい配列
finalize -> 2013-02-18 :1回 呼出す

結論は、
mapのemitで指定するValueのIDの名称とreduceのIDの名称を一致させるべき。(マニュアルにあったけど理解出来なかった。)

良い例)
emit( _id , { u_id : this.user_id, t_c : 1})
reduce (k, v) {
  var rValue = {u_id : "", t_c : 0};
  rValue.t_c += v.t_c;
  rValue.t_c += v.u_id + rValue.u_id;
 return rValue;
}

悪い例)
emit( _id , { user_id : this.user_id, count : 1})
reduce (k, v) {
  var rValue = {u_id : "", t_c : 0};
  rValue.t_c += v.count; // undefinedが発生する可能性有り
  rValue.t_c += v.user_id + rValue.u_id; // undefinedが発生する可能性有り
 return rValue;
}

0 件のコメント:

コメントを投稿