1

私はMongoDBに非常にsimpleMap/Reduce関数を持っています。これは、コレクションからデータセットの平均を返すことを目的としています。答えがちょうど間違っていることを除いて、すべてうまくいくようです。1つのケースでは2倍です。

これが私のMap/Reduce関数です-「diff」値がどこから来ているのかを難読化する必要がありましたが、ログに返されたprintステートメントから正しいことを確認しました:

    var mapFunction = function() {
    if (this.fieldId==1234) {
        print(diff);    
    }
    emit(this.fieldId,diff);
};

var reduceFunction = function(keyId, viewTime) {
    var count = viewTime.length;
    var total = 0;
    for (idx = 0; idx < viewTime.length; idx++) {
        total+=viewTime[idx];
    }
    if (keyVidId==1234) {
        print('1234: ' + total/count);  
    }
    return total/count;
};

これを実行した後、特定のレコード1234について、MySQLから移行する前に得た結果の約2倍になり、スケーラビリティなどのためにMap/Reduceを実行することを決定する前に使用したAggregationFrameworkを使用して得た結果も2倍になります。 。他のレコードも間違っていますが、一般的にはそれほど多くはありません。

当初、reduceFunctionはArray.avgを使用していましたが、デバッグを試みるために手動平均に変換しました。

問題のデータは約23,000のドキュメントであり、各差分は非常に大きな整数になる傾向があります。

何が悪かったのかを調べてログを調べ、LibreOffice Calcを使用してログに出力された差分値を実際に手動で平均し、正しい結果を得たので、エラーはreduce関数の実装のどこかにあります。

ログに「1234:」と書かれた行が複数あることに気づきました。まるで1つのkeyIdに対してreduce関数が複数回呼び出されているかのようです。これがどのように機能しているかはわかりませんが、分割されていると思います。ワークロードを複数の関数呼び出しに分割し、最後に結合します。これは、正しい平均を取得するために結果に重みを付ける必要があることを意味します...問題がどこにあるかは想像できますが、よくわかりません。また、int32オーバーフローであることが心配でした(すべてのdiffの合計が最大値よりも大きいため)が、問題の数値をPythonで少しいじった場合はそうではないようです。

うまくいけば、誰かがMongoDBがバックグラウンドで何をしているのか、そして私が間違っているのかを明らかにすることができます...

ありがとう!

4

1 に答える 1

0

あなたが間違っているのは、ファイナライズ関数で実行する必要がある各reduce(合計と合計に基づく平均)で何かを計算することです(これはオプションですが、提供された場合、キー値ごとに1回だけ実行されます)。

reduce 関数は 0 回、1 回、または複数回呼び出される可能性があるため、reduce でキーに対して発行されたすべての値の配列を取得すると想定することはできません。

これは、キーごとにオブジェクト {total:1, value:diff} を発行し、次に reduce でそれらをインクリメントして、各キーのすべての値を累積する必要があることを意味します。

ファイナライズ機能では、適切な平均を得るために除算を行う場所です。

この例はまさにそれを行っています。

于 2013-05-15T22:50:39.237 に答える