MongoDB mapreduce丢失数据,返回'null'

时间:2012-10-06 03:36:28

标签: mongodb mapreduce

所以这很奇怪。我正在尝试使用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分钟):

[
  {
    "_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 } ]

......数据在某处丢失了吗?

2 个答案:

答案 0 :(得分:13)

MapReduce的第一条规则:

您将从Red中返回与Map中的密钥完全相同的格式。

MapReduce的第二条规则:

您将减少传递的值数组,以便根据需要减少次数。可以多次调用减少功能。

你在reduce的实现中已经破坏了这两个规则。

您的地图功能正在发出键值对。

键:端口名称(您只需将名称作为键,而不是文档)发送 value:表示需要累积的三件事的文档(日期,指标,计数)

请改为尝试:

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;
    }

答案 1 :(得分:1)

尝试在临时集合而不是内存中输出map reduce数据。可能那就是原因。来自Mongo Docs

  

{inline:1} - 使用此选项,不会创建任何集合,并且   整个map-reduce操作将在RAM中发生。还有,结果   map-reduce将在结果对象中返回。注意   仅当结果集符合16MB时,才可以使用此选项   单个文件的限制。在v2.0中,这是您唯一可用的   副本集上的选项。

此外,可能不是原因,但MongoDB在32位机器上的数据大小限制(2GB)。