使用mapreduce查找用户之间的常用项

时间:2012-12-17 22:26:47

标签: mapreduce

假设我有以下用户/项目集,其中项目也可以为每个用户复制(如user1)

{ "u1", "item" : [ "a", "a", "c","h" ] }
{ "u2", "item" : [ "b", "a", "f" ] }
{ "u3", "item" : [ "a", "a", "f" ] }

我想找一个map-reduce算法来计算每对用户之间的常见项目数量

{ "u1_u2", "common_items" : 1 }
{ "u1_u3", "common_items" : 2  }
{ "u2_u3", "common_items" : 2 }

它基本上找到每对项目集的交叉点,并将重复项视为新项目。我是mapreduce的新手,我怎么能做map-reduce呢?

3 个答案:

答案 0 :(得分:3)

由于存在这些问题,您需要了解一些算法比其他算法更好地扩展,任何一种算法的性能都取决于数据的“形状”和大小。

将每个用户的项目集与每个其他用户进行比较可能适用于小型域数据集(比如1000或者用户,甚至可能是10,000,具有相似数量的项目),但是是“n平方”问题(或者就此而言,我的Big O至少可以生锈!):

Users Comparisons
----- -----------
  2       1
  3       3
  4       6
  5       10
  6       15
  n   (n^2 - n)/2

因此,100,000的用户域将产生4,999,950,000个集合比较。

解决此问题的另一种方法是反转关系,因此运行Map Reduce作业以向用户生成项目地图:

'a' : [ 'u1', 'u2', 'u3' ],
'b' : [ 'u2' ],
'c' : [ 'u1' ],
'f' : [ 'u2', 'u3' ],
'h' : [ 'u1' ],

从那里你可以为每个项目迭代用户并输出用户对(计数为1):

'a' would produce: [ 'u1_u2' : 1, 'u1_u3' : 1, 'u2_u3' : 1 ]
'f' would produce: [ 'u2_u3' : 1 ]

然后最终为每个用户配对产生总和:

[ 'u1_u2' : 1, 'u1_u3' : 1, 'u2_u3' : 2 ]

这不会产生您感兴趣的行为(u1和u3项目集中的双重a),但详细说明了初始实现。

如果您知道您的域集通常包含没有共同项目的用户,每个用户的少量项目,或者具有大量不同值的项目域,那么此算法将更有效(之前你将每个用户与另一个用户进行比较,两组之间的交叉概率很低)。我相信数学家可以为你证明这一点,但我不是!

这也有与以前相同的潜在扩展问题 - 因为如果你有一个项目,所有100,000个用户都有共同点,你仍然需要生成40亿用户对。这就是为什么在盲目地应用算法之前了解您的数据很重要。

答案 1 :(得分:2)

您需要一个能够发出用户所有内容的步骤,例如:

{ 'a': "u1" }
{ 'a': "u1" }
{ 'c': "u1" }
{ 'h': "u1" }
{ 'b': "u2" }
{ 'a': "u2" }
{ 'f': "u2" }
{ 'a': "u1" }
{ 'a': "u3" }
{ 'f': "u3" }

然后通过键减少它们:

{ 'a': ["u1", "u1", "u2", "u3"] }
{ 'b': ["u2"] }
{ 'c': ["u1"] }
{ 'f': ["u2", "u3"] }
{ 'h': ["u1"] }

并且该减速器在每个值中发出每个用户的排列,例如:

{ 'u1_u2': 'a' }
{ 'u2_u3': 'a' }
{ 'u1_u3': 'a' }
{ 'u2_u3': 'f' }

请注意,您需要确保使用k1_k2这样的k1 < k2密钥,以便它们在任何进一步的mapreduce步骤中匹配。

然后,如果你需要它们所有分组都像你的例子,另一个mapreduce阶段按键组合它们,它们最终会像:

{ 'u1_u2': ['a'] }
{ 'u1_u3': ['a'] }
{ 'u2_u3': ['a', 'f'] }
{ 'u2_u3': ['f'] }

答案 2 :(得分:0)

这对你有用吗?

from itertools import combinations

user_sets = [
    { 'u1': [ 'a', 'a', 'c', 'h' ] },
    { 'u2': [ 'b', 'a', 'f' ] },
    { 'u3': [ 'a', 'a', 'f' ] },
]

def compare_sets(set1, set2):
    sum = 0
    for n, item in enumerate(set1):
        if item in set2:
            sum += 1
            del set2[set2.index(item)]
    return sum

for set in combinations(user_sets, 2): 
    comp1, comp2 = set[0], set[1]
    print 'Common items bwteen %s and %s: %s' % (
        comp1.keys()[0], comp2.keys()[0], 
        compare_sets(comp1.values()[0], comp2.values()[0])
    )

这是输出:

Common items bwteen u1 and u2: 1
Common items bwteen u1 and u3: 2
Common items bwteen u2 and u3: 1