分档和制表(独特/计数)在蒙戈(Binning and tabulate (unique/count

2019-07-30 13:07发布

我正在寻找一种方法来生成使用Mongo的一些汇总统计。 假设我有一个集合与形式的多条记录

{"name" : "Jeroen", "gender" : "m", "age" :27.53 }

现在,我想为性别和年龄分布。 假设性别,只有值"m""f" 。 什么是让男性和女性的总数在我的收藏中最有效的方法是什么?

而对于年龄,有没有做一些“分级”,给我喜欢总结直方图的方式; 即记录的数量,其中年龄是在间隔: [0, 2), [2, 4), [4, 6) ...等?

Answer 1:

我只是尝试了新的聚合框架,将在MongoDB的2.2版本(2.2.0-RC0已发布)可用,这应该比地图更高的性能降低,因为它不依赖于JavaScript。

输入数据:

{ "_id" : 1, "age" : 22.34, "gender" : "f" }
{ "_id" : 2, "age" : 23.9, "gender" : "f" }
{ "_id" : 3, "age" : 27.4, "gender" : "f" }
{ "_id" : 4, "age" : 26.9, "gender" : "m" }
{ "_id" : 5, "age" : 26, "gender" : "m" }

性别aggregation命令:

db.collection.aggregate(
   {$project: {gender:1}},
   {$group: {
        _id: "$gender",
        count: {$sum: 1}
   }})

结果:

{"result" : 
   [
     {"_id" : "m", "count" : 2},
     {"_id" : "f", "count" : 3}
   ],
   "ok" : 1
}

为了获得在垃圾箱年龄:

db.collection.aggregate(
   {$project: {
        ageLowerBound: {$subtract:["$age", {$mod:["$age",2]}]}}
   },
   {$group: {
       _id:"$ageLowerBound", 
       count:{$sum:1}
   }
})

结果:

{"result" : 
    [
       {"_id" : 26, "count" : 3},
       {"_id" : 22, "count" : 2}
    ],
    "ok" : 1
}


Answer 2:

康斯坦丁的答案是正确的。 MapReduce的能够完成任务。 下面是完整的解决方案的情况下,其他人发现这个有趣。

要统计性别,地图功能键是this.gender对每条记录的属性。 精简函数,然后简单地增加起来:

// count genders
db.persons.mapReduce(
    function(){
        emit(this["gender"], {count: 1})
    }, function(key, values){
        var result = {count: 0};
        values.forEach(function(value) {
            result.count += value.count;
        });
        return result;
    }, {out: { inline : 1}}
);

要做到分级,我们设置的地图功能的关键在于两个向下舍到最近的分裂。 因此,如10和11.9999之间的任意值将得到相同的密钥"10-12" 。 再然后,我们只是把它们相加:

db.responses.mapReduce(
    function(){
        var x = Math.floor(this["age"]/2)*2;
        var key = x + "-" + (x+2);
        emit(key, {count: 1})
    }, function(state, values){
        var result = {count: 0};
        values.forEach(function(value) {
            result.count += value.count;
        });
        return result;
    }, {out: { inline : 1}}
);


Answer 3:

一个简单的方法来获得男性的总数将db.x.find({"gender": "m"}).count()

如果你想在短短的一个查询男性和女性的罪名,那么有没有简单的方法。 地图/减少将是一种可能性。 也许新的聚合框架 。 这同样适用于您的分级要求真

蒙戈也不是很大的聚集,但它是梦幻般的许多小增量更新。 因此,要解决这个问题,蒙戈最好的办法是收集汇总的数据在一个单独的集合。

所以,如果你保持一个统计信息收集与像这样的文件:

stats: [
  {
     "male": 23,
     "female": 17,
     "ageDistribution": {
       "0_2" : 3,
       "2_4" : 5,
       "4_6" : 7
     }
  }
]

...然后每次您添加或从其他集合中删除一个人,你算各自领域的统计信息收集向上或向下。

db.stats.update({"$inc": {"male": 1, "ageDistribution.2_4": 1}})

查询统计将是快如闪电的这种方式,你将很难从上下计数统计发现任何性能开销。



Answer 4:

根据数据最有效的方法量发现男性和女性的数量可能是既天真查询或映射减少工作。 分级通过地图降低做得最好:

在地图阶段的关键是频率区间,和值是1,而在降低阶段,你刚才总结值



Answer 5:

随着蒙戈3.4本刚更加容易,这要归功于新的$桶和$ bucketAuto聚合函数。 下面的查询自动桶分为两类:

db.bucket.aggregate( [
   {
     $bucketAuto: {
         groupBy: "$gender",
         buckets: 2
     }
   }
] )

用下面的输入数据:

{ "_id" : 1, "age" : 22.34, "gender" : "f" }
{ "_id" : 2, "age" : 23.9, "gender" : "f" }
{ "_id" : 3, "age" : 27.4, "gender" : "f" }
{ "_id" : 4, "age" : 26.9, "gender" : "m" }
{ "_id" : 5, "age" : 26, "gender" : "m" }

它提供了以下结果:

{ "_id" : { "min" : "f", "max" : "m" }, "count" : 3 }
{ "_id" : { "min" : "m", "max" : "m" }, "count" : 2 }

注意,水桶和经销商斗通常用于连续变量(数字,日期),但在这种情况下,自动桶工程只是罚款。



Answer 6:

基于@ColinE的装箱的直方图的回答可以这样做

db.persons.aggregate([
  {
  $bucket: {
    groupBy: "$j.age",
    boundaries: [0,2,4,6,8,10,12,14,16,18,20],
    default: "Other",
    output: {
      "count": { $sum: 1 }
    }
  }
],
{allowDiskUse:true})

$bucketAuto因为水桶似乎对数刻度被收集并没有为我工作。 allowDiskUse只需要你有几百万的文件



文章来源: Binning and tabulate (unique/count) in Mongo