【问题标题】:pymongo, map_reduce result not same as mongo command linepymongo,map_reduce 结果与 mongo 命令行不同
【发布时间】:2015-10-25 06:50:16
【问题描述】:

我是 mongodb 的新手,但这只是我的简单测试。 不幸的是,使用相同的 map/reduce 函数,我从 mongo 命令行和 pymongo 得到不同的结果...... Pymongo是3.0.3,mongodb是3.0

下面是命令行操作:

map = function(){
... var date = new Date('2015-07-30');
... emit(date,this)
... }
function (){
var date = new Date('2015-07-30');
emit(date,this)
}

reduce = function(key, values){
... var sum = {'new':0,'act':0,'channel_new':{},'ver_new':{},'channel_ver_new':{}};
... values.forEach(function(doc){
... sum.new += doc.new;
... sum.act += doc.act;
... var category = {"channel_new":1,"ver_new":1,"channel_ver_new":1};
... for(var item in category)
... {
...   var t = Object.keys(doc[item]);
...   for(var i in t){
...    if(Object.keys(sum[item]).indexOf(t[i])!=-1){
...     sum[item][t[i]] += doc[item][t[i]];
...    }else{
...     sum[item][t[i]] = doc[item][t[i]];
...    }
...   }
... }
... });
... return sum;
... }
function (key, values){
var sum = {'new':0,'act':0,'channel_new':{},'ver_new':{},'channel_ver_new':{}};
values.forEach(function(doc){
sum.new += doc.new;
sum.act += doc.act;
var category = {"channel_new":1,"ver_new":1,"channel_ver_new":1};
for(var item in category)
{
  var t = Object.keys(doc[item]);
  for(var i in t){
   if(Object.keys(sum[item]).indexOf(t[i])!=-1){
    sum[item][t[i]] += doc[item][t[i]];
   }else{
    sum[item][t[i]] = doc[item][t[i]];
   }
  }
}
});
return sum;
}
db.daily.mapReduce(map,reduce,{out:"wnitest"})
{
        "result" : "wnitest",
        "timeMillis" : 12,
        "counts" : {
                "input" : 2,
                "emit" : 2,
                "reduce" : 1,
                "output" : 1
        },
        "ok" : 1
}

结果如下:

db.daily.find()
{ "_id" : ObjectId("55bef40cf6d9e26e37e3e37b"), "date" : ISODate("2015-07-06T00:00:00Z"), "new" : 1,
 "channel_ver_new" : { "111_0500_00*#*0\uff0E9\uff0E0" : 2 }, "ver_new" : { "0\uff0E9\uff0E0" : 2 },
 "channel_new" : { "111_0500_00" : 2 } }
{ "_id" : ObjectId("55bef40cf6d9e26e37e3e37d"), "date" : ISODate("2015-07-07T00:00:00Z"), "new" : 2,
 "channel_ver_new" : { "111_0500_00*#*1\uff0E0\uff0E0" : 3 }, "ver_new" : { "1\uff0E0\uff0E0" : 3 },
 "channel_new" : { "111_0500_00" : 3 } }

db.wnitest.find()
{ "_id" : ISODate("2015-07-30T00:00:00Z"), "value" : { "new" : 3, "act" : NaN, "channel_new" : { "11
1_0500_00" : 5 }, "ver_new" : { "0\uff0E9\uff0E0" : 2, "1\uff0E0\uff0E0" : 3 }, "channel_ver_new" :
{ "111_0500_00*#*0\uff0E9\uff0E0" : 2, "111_0500_00*#*1\uff0E0\uff0E0" : 3 } } }
>

这是我的python代码:

mapper = Code("""function(){
var date = new Date('2015-7-30');
emit(date,this);
}""")
reducer = Code("""function(key, values){
var sum = {"new":0,"act":0,"channel_new":{},"ver_new":{},"channel_ver_new":{}};
values.forEach(function(doc){
sum.new += doc.new;
sum.act += doc.act;
var category = {"channel_new":1,"ver_new":1,"channel_ver_new":1};
for(var item in category)
{
  var t = Object.keys(doc[item]);
  for(var i in t){
   if(Object.keys(sum[item]).indexOf(t[i])!=-1){
    sum[item][t[i]] += doc[item][t[i]];
   }else{
    sum[item][t[i]] = doc[item][t[i]];
   }
  }
}
});
return sum;
}
    """)
db.daily.map_reduce(mapper,reducer,'weekly')

Here is result:

> db.weekly.find()
{ "_id" : ISODate("2015-07-29T16:00:00Z"), "value" : { "_id" : ObjectId("55bef4eaf6d9e26e37e3e380"),
 "date" : ISODate("2015-07-06T00:00:00Z"), "new" : 1, "channel_ver_new" : { "111_0500_00*#*0\uff0E9\
uff0E0" : 2 }, "ver_new" : { "0\uff0E9\uff0E0" : 2 }, "channel_new" : { "111_0500_00" : 2 } } }
>

这是对 pymongo 的 map_reduce 的响应:

{u'timing': {u'total': 59, u'mapTime': 0, u'emitLoop': 57, u'mode': u'mixed', u'reduceTime': 0}, u'counts': {u'input': 1, u'reduce': 0, u'emit': 1, u'output': 1}, u'timeMillis': 59, u'ok': 1.0, u'result': u'weekly'}

reduce 为 0,为什么?

【问题讨论】:

  • 好的。代码包含更好。您在这里发出emit(date,this),这似乎有点多余,因为文档中的某处可能有一个“日期”字段。输入的文档结构是什么?您的映射器“输出”与减速器“输出”可能存在差异,这是一个常见的 mapReduce 错误。再次编辑以显示典型文档。
  • 嗨,看看 db.daily.find() 输出,你说得对,它有 'date' 字段,我认为与此无关,当我更改为另一个时仍然相同.似乎 reduce 没有与 pymongo map_reduce 一起运行。
  • 在您的问题上使用“编辑”链接。 cmets中没有代码或数据。
  • 您是否会停止做出自己的假设,请发布您被要求提供的详细信息。如果每个人真正遇到问题都是因为您正在使用的软件中的“错误”,那么世界将陷入停顿。 99.9999% 的时间,问题出在您的代码中。这就是为什么我想查看原始文档格式以供输入。
  • 嗨布莱克斯,已经添加了 db.daily.find() :-)

标签: python mongodb


【解决方案1】:

我不认为这是 python 驱动程序的任何错误,只是您的 reduce 函数一开始就没有正确设置。

为了对所有可能键的值求和,您的代码应该看起来更像这样:

var mapper  = function() {
    delete this.date;
    emit(date,this);
};

var reducer = function(key,values) {
    var reduced = { 
        "new": 0, 
        "channel_new": {}, 
        "ver_new": {}, 
        "channel_ver_new": {} 
    };

    values.forEach(function(value) {
        reduced.new += value.new;

        Object.keys(reduced).filter(function(key) {
            return key != "new";
        }).forEach(function(key){
            if (value.hasOwnProperty(key)) {
                Object.keys(value[key]).forEach(function(iKey) {
                    if (!reduced[key].hasOwnProperty(ikey))
                        reduced[key][ikey] = 0;
                    reduced[key][ikey] += value[key][ikey];
                })
            }
        });
    });

    return reduced;
};

var options = {
    "out": { "inline": 1 },
    "scope": { "date": new Date("2015-07-27") },
    "query": { 
        "date": { 
            "$gte": new Date("2015-07-27"), "$lt": new Date("2015-08-03")
        }
    }
}

db.daily.mapReduce(mapper,reducer,options);

在给定查询范围选择的情况下,可以正确遍历所有元素并正确聚合。

【讨论】:

  • 布莱克,你是对的。我发现当 map_reduce 运行时,实际上 map 输入文档只有一个,所以,reduce 被跳过,然后,只返回任何 map 函数返回。你的代码很不错。谢谢。
  • @Wesley 是的。在经历了从你那里获取信息的所有麻烦之后,很明显减速器的结构不正确。非常感谢您承认我在这里的帮助。
猜你喜欢
  • 2015-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-08
  • 1970-01-01
  • 2018-04-23
  • 2013-11-04
  • 2019-05-04
相关资源
最近更新 更多