mongo-db中对mapReduce查询的响应不正确

时间:2015-06-15 06:49:15

标签: mongodb mapreduce

我在collecton中有1000个用户记录,其中459个文档有性别男性,其余为女性

//document structure
> db.user_details.find().pretty()
{
    "_id" : ObjectId("557e610d626754910f0974a4"),
    "id" : 0,
    "name" : "Leanne Flinn",
    "email" : "leanne.flinn@unilogic.com",
    "work" : "Unilogic",
    "dob" : "Fri Jun 11 1965 20:50:58 GMT+0530 (IST)",
    "age" : 5,
    "gender" : "female",
    "salary" : 35696,
    "hobbies" : "Acrobatics,Meditation,Music"
}
{
    "_id" : ObjectId("557e610d626754910f0974a5"),
    "id" : 1,
    "name" : "Edward Young",
    "email" : "edward.young@solexis.com",
    "work" : "Solexis",
    "dob" : "Wed Feb 12 1941 16:45:53 GMT+0530 (IST)",
    "age" : 1,
    "gender" : "female",
    "salary" : 72291,
    "hobbies" : "Acrobatics,Meditation,Music"
}
{
    "_id" : ObjectId("557e610d626754910f0974a6"),
    "id" : 2,
    "name" : "Haydee Milligan",
    "email" : "haydee.milligan@dalserve.com",
    "work" : "Dalserve",
    "dob" : "Tue Sep 13 1994 13:45:04 GMT+0530 (IST)",
    "age" : 17,
    "gender" : "male",
    "salary" : 20026,
    "hobbies" : "Papier-Mache"
}
{
    "_id" : ObjectId("557e610d626754910f0974a7"),
    "id" : 3,
    "name" : "Lyle Keesee",
    "email" : "lyle.keesee@terrasys.com",
    "work" : "Terrasys",
    "dob" : "Tue Apr 25 1922 13:39:46 GMT+0530 (IST)",
    "age" : 79,
    "gender" : "female",
    "salary" : 48032,
    "hobbies" : "Acrobatics,Meditation,Music"
}
{
    "_id" : ObjectId("557e610d626754910f0974a8"),
    "id" : 4,
    "name" : "Shea Mercer",
    "email" : "shea.mercer@pancast.com",
    "work" : "Pancast",
    "dob" : "Mon Apr 08 1935 06:10:30 GMT+0530 (IST)",
    "age" : 51,
    "gender" : "male",
    "salary" : 31511,
    "hobbies" : "Acrobatics,Photography,Papier-Mache"
}

每个性别的用户数

> db.user_details.find({gender:'male'}).count()
459
> 
> db.user_details.find({gender:'female'}).count()
541



> db.user_details.find({name:{$ne:null}}).count()
1000
> db.user_details.find({age:{$ne:null}}).count()
1000

地图缩减代码

mapper = function(){
  emit(this.gender, {name:this.name,age:this.age})
}

reducer = function(gender, users){
  var res = 0;
  users.forEach(function(user){
    res = res + 1
  })
  return res;
}


db.user_details.mapReduce(mapper, reducer, {out: {inline:1}})

为什么map reduce结果只有112个文件?男性和女性应分别包含459和541,不是吗?

// Map reduce result
{
  "results" : [
    {
      "_id" : "female",
      "value" : 56
    },
    {
      "_id" : "male",
      "value" : 46
    }
  ],
  "timeMillis" : 45,
  "counts" : {
    "input" : 1000,
    "emit" : 1000,
    "reduce" : 20,
    "output" : 2
  },
  "ok" : 1
}

注意:我知道这不是使用map reduce的正确方法,实际上我在map reduce中面临一些更令人毛骨悚然的问题。一旦我得到这个问题的解决方案,我就可以解决这个问题

4 个答案:

答案 0 :(得分:1)

你的问题在于你错过了mapReduce如何工作的核心概念之一。找到解释此问题的相关文档here

  
      
  • MongoDB可以为同一个密钥多次调用reduce函数。在这种情况下,该键的reduce函数的先前输出将成为该键的下一个reduce函数调用的输入值之一。
  •   

然后又过了一​​会儿:

  
      
  • 返回对象的类型必须与map函数
  • 发出的值的类型相同   

这两个陈述的含义是您需要使用映射器 reducer 函数发出的完全相同签名作为<强>减少过程确实会被多次调用#34;。

这就是mapReduce处理大数据的方式,但不一定要为给定的&#34;键&#34;处理所有相同的值。立刻,但在增量&#34;块&#34;:

如果输出中你想要的只是一个&#34;数字&#34;然后你所有&#34;发出&#34;只是一个&#34;数字&#34;以及:

db.collection.mapReduce(
    function() {
       emit(this.gender, this.age);
    },
    function(key,values) {
        return Array.sum( values )
    },
    { "out": { "inline": 1 } }
)

或者只是&#34;计算&#34;每种类型:

db.collection.mapReduce(
    function() {
       emit(this.gender, 1);
    },
    function(key,values) {
        return Array.sum( values )
    },
    { "out": { "inline": 1 } }
)

关键是&#34;你需要把你输入的内容和#34;放在一起,因为它很可能会再次回到&#34;。因此,无论您要收集哪些数据,mapper和reducer 的输出结构必须相同。

答案 1 :(得分:0)

这可能是错误的。

users.forEach(function(user){
    res = res + 1
  })

试试这个,

function(gender, users){
   return Array.sum( users)
}

答案 2 :(得分:0)

减少功能有误。

MONGODB reduce函数可以为同一个KEY多次调用,因此在你的reduce代码中它被覆盖。

同样在map函数中,您正在发出结构{user,age}的文档,但在reduce函数中,您将返回计数。

  reduce = function(gender, doc) {
                 reducedVal = { user: 0, age: 0 };

                 for (var idx = 0; idx < doc.length; idx++) {
                     reducedVal.user += 1 ;
                     reducedVal.age += 1;
                 }

                 return reducedVal;
              };

请查看以下链接:

http://thejackalofjavascript.com/mapreduce-in-mongodb/

答案 3 :(得分:0)

这是使用地图reduce()的正确方法,用于按性别显示用户数

    db.yourCollectionName.mapReduce(
       function(){
           emit(this.gender,1);
       },
       function(k,v){
          return Array.sum(v);
       },
       {out:"genderCount"}
    );
    db.genderCount.find();