2012-07-23 62 views
7

我正在尋找一種方法來生成使用蒙戈一些彙總統計。假設我有一個形式分檔和製表(獨特/計數)在蒙戈

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

的多條記錄的集合現在我想對性別和年齡分佈。假定性別,只有值"m""f"。在我的收藏中獲得男性和女性總人數的最有效方法是什麼?

而且年齡,有沒有做一些「分級」,給我喜歡總結直方圖的方式;即年齡在區間內的記錄數:[0, 2), [2, 4), [4, 6) ...等?

回答

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}} 
); 
+0

這是很酷的。我在哪裏可以找到mapReduce()函數的文檔?我做了搜索,但似乎沒有找到官方消息來源... – jimijazz 2016-02-16 13:04:04

0

根據數據量,找到男性和女性的數量的最有效方法可以是天真查詢或地圖縮減作業 。分級是通過地圖做得最好減少:

在地圖階段的關鍵是頻率區間,和值是1,而在降低階段,你剛纔總結值

+0

你能說明這一點的一些示例代碼? – Jeroen 2012-07-23 22:17:04

+0

你是快 - 我在度假,差不多離線 – 2012-07-25 19:49:35

1

一個簡單的方法來獲得的總計數如果你想無論是男性,並在短短一個查詢女性計數,那麼有沒有簡單的方法男性會db.x.find({"gender": "m"}).count()

。地圖/縮小將是一種可能性。或者也許是新的aggregation frameworkbinning要求

Mongo對於聚合並不是很好,但對於許多小的增量更新來說,這是非常棒的。 所以要解決這個問題,蒙戈最好的辦法是收集彙總的數據在一個單獨的集合。

所以,如果你保持一個統計信息收集與一個文檔這樣的:

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

查詢到的統計信息將是快如閃電的這種方式,你將很難從上下計數統計發現任何性能開銷。

19

我只是嘗試了新的聚合框架,將在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" } 

聚集命令:

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 
} 
+0

我還應該注意,對於任何對聚合框架感興趣的用戶,建議儘早在聚集命令中使用$ match,以防止全表掃描。 – Jenna 2012-07-25 14:58:23

+2

對於不是有些數倍任意箱,你可以使用[$ COND(http://docs.mongodb.org/manual/reference/operator/aggregation/cond/#exp._S_cond)雖然語法可怕的: $ project:{ageLowerBound: {$ cond:[{$ lt:[$ age,2]},「0」, {$ cond:[{$ lt:[$ age,4]}, 「2」, 「4」]}]}} ...或者類似的東西。 – 2015-04-21 10:05:14

+0

@Jenna我們可以做對GeoJSON的項目是什麼? – Pei 2017-08-11 03:07:25

0

隨着蒙戈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 } 

注意,水桶和經銷商鬥通常用於連續變量(數字,日期),但在這種情況下,自動存儲桶工作得很好。

0

基於@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只需要你有幾百萬的文件