5

だからこれは奇妙です。mapreduce を使用して、一意のポートで日時/メトリックをグループ化しようとしています:

ドキュメントのレイアウト:

{
        "_id" : ObjectId("5069d68700a2934015000000"),
        "port_name" : "CL1-A",
        "metric" : "340.0",
        "port_number" : "0",
        "datetime" : ISODate("2012-09-30T13:44:00Z"),
        "array_serial" : "12345"
}

および mapreduce 関数:

var query = {
        'array_serial' : array,
        'port_name' : { $in : ports },
        'datetime' : { $gte : from, $lte : to}

    }

    var map = function() {
        emit( { portname : this.port_name } , { datetime : this.datetime,
                                metric : this.metric });
    }

    var reduce = function(key, values) {
        var res = { dates : [], metrics : [], count : 0}

        values.forEach(function(value){
            res.dates.push(value.datetime);
            res.metrics.push(value.metric);
            res.count++;
        })

        return res;
    }

    var command = {
        mapreduce : collection,
        map : map.toString(),
        reduce : reduce.toString(),
        query : query,
        out : { inline : 1 }

    }

    mongoose.connection.db.executeDbCommand(command, function(err, dbres){
        if(err) throw err;
        console.log(dbres.documents);
        res.json(dbres.documents[0].results);
    })

5、10、または 60 などの少数のレコードが要求された場合、期待どおりのすべてのデータが返されます。より大きなクエリは、切り捨てられた値を返します....


さらにテストを行ったところ、レコード出力が 100 に制限されているようです。これは詳細なデータであり、24 時間クエリを実行すると、1440 レコードが返されると予想されます... 80 を受け取って実行しただけです。:\

これは期待されていますか?私が言うことができるどこにも制限を指定していません...


その他のデータ:

2012-10-01T23:00 ~ 2012-10-02T00:39 (100 分) のレコードに対するクエリは、次のように正しく返されます。

[
  {
    "_id": {
      "portname": "CL1-A"
    },
    "value": {
      "dates": [
        "2012-10-01T23:00:00.000Z",
        "2012-10-01T23:01:00.000Z",
        "2012-10-01T23:02:00.000Z",
         ...cut...
        "2012-10-02T00:37:00.000Z",
        "2012-10-02T00:38:00.000Z",
        "2012-10-02T00:39:00.000Z"
      ],
      "metrics": [
        "1596.0",
        "1562.0",
        "1445.0",
        ...cut...
        "774.0",
        "493.0",
        "342.0"
      ],
      "count": 100
    }
  }
]

...クエリ 2012-10-01T23:00 - 2012-10-02T00:39 (101 minutes) にもう 1 分追加します。

[
  {
    "_id": {
      "portname": "CL1-A"
    },
    "value": {
      "dates": [
        null,
        "2012-10-02T00:40:00.000Z"
      ],
      "metrics": [
        null,
        "487.0"
      ],
      "count": 2
    }
  }
]

オブジェクトは、dbres.documents正しいと予想される出力されたレコードを示します。

[ { results: [ [Object] ],
    timeMillis: 8,
    counts: { input: 101, emit: 101, reduce: 2, output: 1 },
    ok: 1 } ]

...データがどこかに失われていますか?

4

2 に答える 2

13

MapReduce のルール 1:

Map でキーを使用して発行したのとまったく同じ形式を Reduce から返す必要があります。

MapReduce のルール 2:

reduce に渡された値の配列を、必要な回数だけ減らします。Reduce 関数は何度も呼び出される可能性があります。

reduce の実装では、これらのルールの両方を破っています。

Map 関数がキーと値のペアを発行しています。

キー: ポート名 (ドキュメントではなく、単にキーとして名前を発行する必要があります)
値: 蓄積する必要がある 3 つのもの (日付、メトリック、カウント) を表すドキュメント

代わりにこれを試してください:

map = function() {  // if you want to reduce to an array you have to emit arrays
    emit ( this.port_name, { dates : [this.datetime], metrics : [this.metric], count: 1 });
}

reduce = function(key, values) {        // for each key you get an array of values
   var res = { dates: [], metrics: [], count: 0 };  // you must reduce them to one

   values.forEach(function(value) {
            res.dates = value.dates.concat(res.dates);
            res.metrics = value.metrics.concat(res.metrics);
            res.count += value.count;   // VERY IMPORTANT reduce result may be re-reduced
        }) 

        return res;
    }
于 2012-10-06T05:52:46.533 に答える
1

メモリ内ではなく、一時コレクション内に map reduce データを出力してみてください。それが理由かもしれません。モンゴドキュメントから:

{ inline : 1} - このオプションを使用すると、コレクションは作成されず、map-reduce 操作全体が RAM で行われます。また、map-reduce の結果は結果オブジェクト内に返されます。このオプションは、結果セットが 1 つのドキュメントの 16 MB の制限内に収まる場合にのみ使用できることに注意してください。v2.0 では、これがレプリカ セット セカンダリで使用できる唯一のオプションです。

また、それが理由ではないかもしれませんが、MongoDB には 32 ビット マシンでのデータ サイズの制限 (2GB) があります。

于 2012-10-06T04:12:27.397 に答える