Spark中笛卡尔的替代品?

时间:2015-10-02 12:18:04

标签: python mapreduce apache-spark combinations pyspark

我有这种类型的RDD:

[(1, [3, 10, 11]), (2, [3, 4, 10, 11]), (3, [1, 4]), (4, [2, 3, 10])...]

我需要一个遵循这条规则的函数:

如果密钥x在其值列表中不包含密钥y(反之亦然),则输出具有以下语法的元组:

[(x, [y, len(values_x ^ values_y)]), ...]

其中len(values_x ^ values_y)是两个键之间共同的值的数量。如果此值为0(即,没有共同的值),则只需跳过这对密钥。

例如,从上面的示例中,输出应为:

(1, [2, 3]) # because keys 1 and 2 share the values 3, 10, 11
(1, [4, 2]) # because keys 1 and 4 share the values 3, 10
skipping: (2, [1, 3]) is the inverse of (1, [2, 3]), so it can be skipped
(2, [3, 1]) # because keys 2 and 3 share the value 4
...

跳过一对密钥13(以及其他类似情况),因为密钥3的列表值中包含密钥1,反之亦然

我已经实施的解决方案(但我根本不喜欢),正在使用cartesian函数创建密钥之间的所有组合,然后使用映射和过滤来删除不必要的配对。

没有使用cartesian是否有更好的解决方案?

1 个答案:

答案 0 :(得分:3)

首先让我们定义一些帮手:

def swap(x):
    """Given a tuple (x1, x2) return (x2, 1)"""
    return (x[1], 1)

def filter_source(x):
    """Check if s1 < s2 in (x, (s1, s2))"""
    return x[1][0] < x[1][1]

def reshape(kv):
    """Reshape ((k1, k2), v) to get final result"""
    ((k1, k2), v) = kv
    return (k1, (k2, v))

并创建一个示例RDD:

rdd = sc.parallelize([
    (1, [3, 10, 11]), (2, [3, 4, 10, 11]),
    (3, [1, 4]), (4, [2, 3, 10])])

最后你可以这样做:

from operator import add

flattened = rdd.flatMap(lambda kv: ((v, kv[0]) for v in kv[1])) # Flatten input
flattened.first()
# (1, 3) <- from (3, [1, 4])

result = (flattened 
    .join(flattened) # Perform self join using value from input as key
    .filter(filter_source) # Remove pairs from the same source
    .map(swap)
    .reduceByKey(add)
    .map(reshape)) # Get final output