2012-03-25 9 views
4

大量のデータを1つのコレクションに集めようとしていましたが、そこに到達するためにMapReduce関数を書く際に問題があります。MongoDBコレクションのMapReduceが空になっています

これは私のデータは次のようになります(ここでは、実際に私が4+万人を持って、17行です):

{"user": 1, "day": 1, "type": "a", "sum": 10} 
{"user": 1, "day": 2, "type": "a", "sum": 32} 
{"user": 1, "day": 1, "type": "b", "sum": 11} 
{"user": 2, "day": 4, "type": "b", "sum": 2} 
{"user": 1, "day": 2, "type": "b", "sum": 1} 
{"user": 1, "day": 3, "type": "b", "sum": 9} 
{"user": 1, "day": 4, "type": "b", "sum": 12} 
{"user": 2, "day": 2, "type": "a", "sum": 3} 
{"user": 3, "day": 2, "type": "b", "sum": 81} 
{"user": 1, "day": 4, "type": "a", "sum": 22} 
{"user": 1, "day": 5, "type": "a", "sum": 39} 
{"user": 2, "day": 5, "type": "a", "sum": 8} 
{"user": 2, "day": 3, "type": "b", "sum": 1} 
{"user": 3, "day": 3, "type": "b", "sum": 99} 
{"user": 2, "day": 3, "type": "a", "sum": 5} 
{"user": 1, "day": 3, "type": "a", "sum": 41} 
{"user": 3, "day": 4, "type": "b", "sum": 106} 
... 

私は配列(それが最終的にこのように見えるように取得しようとしています内容は日によって決定された適切なインデックスでちょうど合計され、各タイプ、その日はそのタイプのために存在しない場合、それは)ちょうど0だため:

{"user": 1, "type_a_sums": [10, 32, 41, 22, 39], "type_b_sums": [11, 1, 9, 12, 0]} 
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]} 
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 81, 99, 106, 0]} 
... 

これは私がされているMapReduceのです試着:

var mapsum = function(){ 
    var output = {user: this.user, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: this.type, tempSum: this.sum, tempDay: this.day} 

    if(this.type == "a") { 
     output.type_a_sums[this.day-1] = this.sum; 
    } 

    if(this.type == "b") { 
     output.type_b_sums[this.day-1] = this.sum; 
    } 

    emit(this.user, output); 
}; 

var r = function(key, values) { 
    var outs = {user: 0, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: -1, tempSum: -1, tempDay: -1} 

    values.forEach(function(v){ 

     outs.user = v.user; 

     if(v.tempType == "a") { 
      outs.type_a_sums[v.tempDay-1] = v.tempSum; 
     } 

     if(v.tempType == "b") { 
      outs.type_b_sums[v.tempDay-1] = v.tempSum; 
     } 

    }); 

    return outs; 
}; 


res = db.sums.mapReduce(mapsum, r, {out: 'joined_sums'}) 

これは私の小さなサンプルで私の出力が得られますが、私はすべて400万それを上に実行したときに、私は次のようになり出力のトンを得る:

usersの大部分を持っている必要があり
{"user": 1, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]} 
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]} 
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]} 

それらの配列の合計は、実際には実際の関数でそれを埋める前にreduce関数outsオブジェクトのダミー配列にあった0で埋められています。

同じコレクションで同じ正確な関数を実行しても1人のユーザーのみを確認すると、実際には奇妙です。res = db.sums.mapReduce(mapsum, r, {query: {user: 1}, out: 'joined_sums'})配列に合計があるはずですが、以前はすべて0になっていますそのユーザーのために必要な出力。 4百万を超えるすべてを再び実行して、私はどこにでも戻ってきます。ダミーフィラーアレイで行ったすべての作業を書いているようなものです。

データが多すぎますか?それは時間を与えられてそれをスロッグすることはできませんか?それとも私は知らない障壁に当たっていますか?

+0

MongoDBの古いバージョンのバグ? – maerics

+0

私は 'reduce()'がキーごとに複数回呼び出されることと関連があると思います。私は 'finalize'を使用しようとしていますが、どのように動作するのか非常に混乱しています。 – TFX

答えて

2

多くの詳細を含めていただきありがとうございます。ここにいくつかの問題があります。

トップから始めましょう。

私は最終的にはこのように見えるようにそれを取得しようとしている

{ "ユーザー":2、 "type_a_sums":[0、3、5、0、8]、 "type_b_sums" :[0、0、1、2、0]}

それは実際にこのようになります。

{ _id: { "user": 2 }, value: { "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0] } 

注意_idは "によってグループ" の種類のあなたのようなもので、valueは一種のあることあなたの「合計」列のように。

問題番号1は、あなたが鍵としてuserを放出していることですが、それはあなたの価値の一部です。これは必要ではありません。 outs.user = v.user;

あなたはまた、問題#2を持っている:あなたのreduceが間違っあるだけ同じ鍵を共有する2つの値を削減する削減は、この行のいずれかを必要としません。

私は、reduce()がキーごとに複数回呼び出されていると考えています。

reduce()の目標は、複数回呼び出されることです。サーバー間で拡張されているはずです。そのため、1台のサーバーで2倍の時間短縮を呼び出すと、その結果をマージして別のサーバーに送信できます。

これは別の方法です。 Reduceはvalueオブジェクトの配列を取り、単一のvalueオブジェクトに縮小します。

いくつかの帰結がここにあります

  • 私はreduce([a, b])をすれば、それはreduce([b, a])と同じである必要があります。
  • 私はreduce([a, reduce([b,c]))をすれば、それはreduce([reduce([a,b]), c])

と同じでなければなりませんだから、私はそれらを実行どのような順序や値が減少します回数は問題ないはず、それは常に同じ出力です。

コードを見ると、これは起こっていません。 type_a_sumsをご覧ください。次の2つを減らすとどうなりますかvalues

reduce([ [0,0,1,0,0], [0,2,0,0,0] ]) => ??? 

私には、これは出力が[0,2,1,0,0]であるように見えます。これが当てはまる場合は、それらのフィールドのすべてを必要としません。temp_Xその代わりに、適切な配列をemitに集中させ、それらの配列を正しくマージする必要があります。

+0

ありがとう!私はコード(http://pastie.org/private/dc9gizrsrzckzq6hvjkqq)を変更しましたが、朝まで実行することはできません。 temp値を削除し、 'reduce()'のコードを変更して、各 'emit()'配列の要素を 'reduce()'出力配列の対応する要素に追加しました。それは理にかなっていますか? なぜ私はちょうど配列を使用すると助けになるのか分かりません。 'temp'変数の要素を追加しないのはなぜでしょうか。この方法では、配列の要素を使って 'int'の代わりに追加するだけですが、同じことだと思います。 'ファイナライズする '必要がありますか? – TFX

+0

*これははるかに優れています。あなたがtempsを必要としない理由は、emit *の出力が最終結果になる可能性があるからです。それは*できないかもしれないが、*可能であるかもしれない。あなたが一日の終わりに本当に欲しいのは配列なので、配列を各段階で正確にしたいと思っています。 –

関連する問題