2012-06-29 63 views
0

我想要在我們的應用中聚合一堆用戶配置文件數據。每個用戶都有一個包含性別和種族屬性的嵌入式配置文件。地圖/減少以獲取組()結果

{ 
    'email': '[email protected]', 
    'profile': { 
    'gender': 'male', 
    'ethnicity': 'Hispanic' 
    } 
} 

如果我使用像這樣一組功能:

db.respondents.group({ 
    key: {}, 
    initial: {'gender': {'male':0,'female':0}, 'ethnicity': {}, 'count': 0}, 
    reduce: function (user, totals) { 
    var profile = user.profile; 

    totals.gender[profile.gender]++; 
    totals.ethnicity[profile.ethnicity] = (totals.ethnicity[profile.ethnicity] || 0); 
    totals.ethnicity[profile.ethnicity]++ 
    totals.count++; 
} 
}); 

我得到的結果的形式我想:

{ 
    "gender" : { 
     "male" : ###, 
     "female" : ### 
    }, 
    "ethnicity" : { 
     "Caucasian/White" : ###, 
     "Hispanic" : ###, 
        ... 

    }, 
    "count" : ### 
} 

我無法得到這個工作作爲一個map/reduce命令,當然使用不同的reduce函數。我不知道如何讓總數加起來。他們總是不正確的。我知道我的縮減輸出必須與地圖輸入格式相同,但我覺得我在減少作品的方式上錯過了一些東西...

爲了迴應@Jenna,輸入的樣子:

{ 
    'email': '[email protected]', 
    'profile': { 
    'gender': 'male', 
    'ethnicity': 'Hispanic' 
    } 
} 

和功能是:

function map(){ 
    emit('demographics', this.profile) 
} 

function reduce (key, values) { 
    var reduced = {'gender': {'male':0,'female':0}, 'ethnicity': {}, 'count': 0}; 
    values.forEach(function(value) { 
    reduced.gender[value.gender]++; 
    reduced['ethnicity'][value.ethnicity] = (reduced['ethnicity'][value.ethnicity] || 0); 
    reduced['ethnicity'][value.ethnicity]++; 
    reduced.count++; 
    }); 
    return reduced; 
} 

並且輸出是:

{ 
    "_id": "demographics", 
    "value": { 
     "gender": { 
     "male": 76.0, 
     "female": 64.0 
     }, 
     "ethnicity": { 
     "Caucasian/White": 109.0, 
     "Other": 5.0, 
     "Asian": 10.0, 
     "African-American": 8.0, 
     "Hispanic": 7.0, 
     "Native American": 1.0 
     }, 
     "count": 141.0 
    } 
} 

輸出方式不正確,因爲數據庫中有超過100k條記錄。

+0

你可以發佈你的地圖和減少功能,以及你的輸入和輸出的例子嗎? – Jenna

+0

@Jenna - 我在帖子中添加了其他信息。謝謝參觀! – RipTheJacker

+0

沒問題:)你還可以發佈當你運行地圖縮小命令時打印的統計數據嗎?例如,當我在shell中運行map reduce時,它會輸出以下字段:result,timeMillis,counts:{input:x,emit:y,reduce:z,output:x} – Jenna

回答

2

可以在早期調用的輸出中再次調用reduce函數。你是正確的,map的輸出應該和reduce的輸出相同。您當前的地圖功能會返回與您的縮小功能不同的內容。嘗試這樣的:

function map(){ 
    result = {'gender': {'male': 0, 'female': 0}, 'ethnicity': {}, 'count': 1}; 
    result['gender'][this.gender] = 1; 
    result['ethnicity'][this.ethnicity] = 1; 
    emit('demographics', result); 
} 

function reduce (key, values) { 
    var reduced = {'gender': {'male':0,'female':0}, 'ethnicity': {}, 'count': 0}; 
    values.forEach(function(value) { 
    reduced['gender']['male'] += value['gender']['male']; 
    reduced['gender']['female'] += value['gender']['female']; 
    for(ethnicity in value['ethnicity']){ 
     if(reduced['ethnicity'][ethnicity] === undefined) 
     reduced['ethnicity'][ethnicity] = 0 
     reduced['ethnicity'][ethnicity] += value['ethnicity'][ethnicity] 
    } 
    reduced['count'] += values.count; 
    }); 
    return reduced; 
} 
+0

「reduce函數可能會在從早期通話輸出「哦。這是我失蹤的一塊。謝謝! – RipTheJacker

+0

很好的例子,謝謝! – Bushikot