将具有多个值成分的两个RDD连接起来并展平结果

时间:2018-12-05 16:11:44

标签: python apache-spark pyspark rdd

我有2个RDD,它们的键相同,但是值类型不同(超过2个值)。我想按键加入这些RDD,然后将它们的值附加到最后一个元组中(请参见下文)。最好的方法是什么?

rdd1 = sc.parallelize([ (1, "test1", [5,6,7]), (2, "test2", [1,2,3]) ])
rdd2 = sc.parallelize([ (1, "Foo"), (2, "Bar") ])

所需的输出RDD

[ (1, "Foo", "test1", [5,6,7]), (2, "Bar", "test2", [1,2,3]) ]

进行直接联接不起作用:

print(rdd2.join(rdd1).collect())
#[(1, ('Foo', 'test1')), (2, ('Bar', 'test2'))]

这将忽略rdd1中其余的值,并且输出格式错误。

1 个答案:

答案 0 :(得分:2)

可以在此处使用join,前提是您首先将rdds映射为(key, value)形式。

rdd1 = sc.parallelize([ (1, "test1", [5,6,7]), (2, "test2", [1,2,3]) ])
rdd2 = sc.parallelize([ (1, "Foo"), (2, "Bar") ])

def map_to_kvp(row):
    if len(row) < 3:
        return row
    return (row[0], tuple(row[1:]))

rdd3 = rdd2.map(map_to_kvp).join(rdd1.map(map_to_kvp))
print(rdd3.collect())
#[
#    (1, ('Foo', ('test1', [5, 6, 7]))), 
#    (2, ('Bar', ('test2', [1, 2, 3])))
#]

现在,所有数据都放在正确的位置,但是您只需要拼合结果行。

在这种情况下,您将必须编写自己的flatten函数,以避免同时平展stringlist

我们可以在this answerHow can I flatten lists without splitting strings?的基础上实现自己的功能:

def flatten(foo):
    for x in foo:
        if hasattr(x, '__iter__') and not isinstance(x, str) and not isinstance(x, list):
            for y in flatten(x):
                yield y
        else:
            yield x

rdd4 = rdd3.map(lambda row: tuple(flatten(row)))
print(rdd4.collect())
#[(1, 'Foo', 'test1', [5, 6, 7]), (2, 'Bar', 'test2', [1, 2, 3])]