2012-12-17 33 views
2

我是新來的mongodb,我想知道是否可以得到一些建議。我有以下集合mongodb中的兩兩交叉點

{ "_id" : "u1", "item" : [ "a", "b", "c" ] } 
{ "_id" : "u2", "item" : [ "b", "d", "e" ] } 
{ "_id" : "u3", "item" : [ "a", "c", "f" ] } 
{ "_id" : "u4", "item" : [ "c" ] } 

我想創建一個新的集合,將在端計算項的並和交對於每一對用戶的,例如,對於用戶1和2,4-結果將是

{ "_id" : "u12", "intersect_count":1,"union_count":6 } 
{ "_id" : "u14", "intersect_count":1,"union_count":4} 

我不想爲每對配對操作,因爲效率低下。有沒有什麼竅門可以更有效地做到這一點?

+0

你的意思是,union_count:6還是應該是u12的5?以及u14不應該union_count爲3. –

+0

我不排除重複,這就是爲什麼我有這些計數 – user1848018

+0

好吧,所以聯合計數只是2個數組長度的總和? –

回答

2

我的解決辦法是這樣的:

map_func = function() { 
    self = this; 
    ids.forEach(function(id) { 
    if (id === self._id) return; 
    emit([id, self._id].sort().join('_'), self.item); 
    }); 
}; 

reduce_func = function(key, vals) { 
    return { 
    intersect_count: intersect_func.apply(null, vals).length, 
    union_count: union_func.apply(null, vals).length 
    }; 
}; 

opts = { 
    out: "redused_items", 
    scope: { 
    ids: db.items.distinct('_id'), 
    union_func: union_func, 
    intersect_func: intersect_func 
    } 
} 

db.items.mapReduce(map_func, reduce_func, opts) 

如果您有您的收藏N elemets然後map_func將發出對未來減少N*(N-1)元素。然後reduce_func將其減少爲N*(N-1)/2新元素。

我以前scope全局變量(ids)和輔助方法(union_funcintersect_func)通入map_funcreduce_func。否則MapReduce將失敗,並出現錯誤,因爲它在特殊環境下評估map_funcreduce_func

結果調用的MapReduce:

> db.redused_items.find() 
{ "_id" : "u1_u2", "value" : { "intersect_count" : 1, "union_count" : 6 } } 
{ "_id" : "u1_u3", "value" : { "intersect_count" : 2, "union_count" : 6 } } 
{ "_id" : "u1_u4", "value" : { "intersect_count" : 1, "union_count" : 4 } } 
{ "_id" : "u2_u3", "value" : { "intersect_count" : 0, "union_count" : 6 } } 
{ "_id" : "u2_u4", "value" : { "intersect_count" : 0, "union_count" : 4 } } 
{ "_id" : "u3_u4", "value" : { "intersect_count" : 1, "union_count" : 4 } } 

我用下面的助手對我的測試:

union_func = function(a1, a2) { 
    return a1.concat(a2); 
}; 

intersect_func = function(a1, a2) { 
    return a1.filter(function(x) { 
    return a2.indexOf(x) >= 0; 
    }); 
}; 

另一種方法是使用蒙戈光標而不是全局ids對象:

map_func = function() { 
    self = this; 
    db.items.find({},['_id']).forEach(function(elem) { 
    if (elem._id === self._id) return; 
    emit([elem._id, self._id].sort().join('_'), self.item); 
    }); 
}; 

opts = { 
    out: "redused_items", 
    scope: { 
    union_func: union_func, 
    intersect_func: intersect_func 
    } 
} 

db.items.mapReduce(map_func, reduce_func, opts) 

結果將是相同的。

+0

我不知道如何感謝你。這非常有幫助。非常感謝 – user1848018