2012-12-17 31 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