复杂的spark连接:rdd元素有很多键值对

时间:2015-05-15 12:51:27

标签: join rdd pyspark

我是新手,试图找到一种方法将信息从一个rdd集成到另一个rdd,但是它们的结构不适合标准的连接函数

我有这种格式的rdd:

[{a:a1, b:b1, c:[1,2,3,4], d:d1},
 {a:a2, b:b2, c:[5,6,7,8], d:d2}]

以及另一种格式:

[{1:x1},{2,x2},{3,x3},{4,x4},{5,x5},{6,x6},{7,x7},{8,x8}]

我想将第二个rdd中的值与第一个rdd中的键匹配(它们位于c键的列表值中)。我知道如果他们在那里操纵它们,所以我不太关心最终输出,但我可能希望看到这样的东西:

[{a:a1, b:b1, c:[1,2,3,4],c0: [x1,x2,x3,x4], d:d1},
 {a:a2, b:b2, c:[5,6,7,8],c0: [x5,x6,x7,x8], d:d2}]

或者这个:

[{a:a1, b:b1, c:[(1,x1),(2,x2),(3,x3),(4,x4)], d:d1},
 {a:a2, b:b2, c:[(5,x5),(6,x6),(7,x7),(8,x8)], d:d2}]

或其他任何可以匹配第二个rdd中的键与第一个中的值的内容。我考虑将第二个rdd变成一个字典,我知道如何使用它,但我认为我的数据太大了。

非常感谢你,我真的很感激。

2 个答案:

答案 0 :(得分:1)

join之后

flatMap,或cartesian进行了太多的随机播放。

其中一种可能的解决方案是在cartesian之后groupBy使用HashPartitioner

(抱歉,这是scala代码)

val rdd0: RDD[(String, String, Seq[Int], String)]
val rdd1: RDD[(Int, String)]

val partitioner = new HashPartitioner(rdd0.partitions.size)

// here is the point!
val grouped = rdd1.groupBy(partitioner.getPartition(_))

val result = rdd0.cartesian(grouped).map { case (left, (_, right)) =>
    val map = right.toMap
    (left._1, left._2, left._4) -> left._3.flatMap(v => map.get(v).map(v -> _))
}.groupByKey().map { case (key, value) =>
    (key._1, key._2, value.flatten.toSeq, key._3)
}

答案 1 :(得分:1)

我将假设rdd1是包含{a:a1, b:b1, c:[1,2,3,4], d:d1}的输入,而rdd2包含元组[(1, x1), (2, x2), (3, x3), (4, x4), (5, x5), (6, x6), (7, x7), (8, x8)]。我还将假设" c"中的所有值。 rdd1中的字段可以在rdd2中找到。如果没有,您需要更改下面的一些代码。

我有时必须解决这类问题。如果rdd2足够小,我通常会进行地图侧连接,首先广播对象,然后进行简单的查找。

def augment_rdd1(line, lookup):
    c0 = []
    for key in line['c']:
        c0.append(lookup.value[key])
    return c0

lookup = sc.broadcast(dict(rdd2.collect()))
output = rdd1.map(lambda line: (line, augment_rdd1(line, lookup)))

如果rdd2太大而无法广播,我通常会使用flatMaprdd1的每一行映射到与&中的元素一样多的行34; C"场,例如{a:a1, b:b1, c:[1,2,3,4], d:d1}将映射到

  • (1, {a:a1, b:b1, c:[1,2,3,4], d:d1})
  • (2, {a:a1, b:b1, c:[1,2,3,4], d:d1})
  • (3, {a:a1, b:b1, c:[1,2,3,4], d:d1})
  • (4, {a:a1, b:b1, c:[1,2,3,4], d:d1})

flatMap是

flat_rdd1 = rdd1.flatMap(lambda line: [(key, line) for key in line['c'])])

然后,我将与rdd2一起获得一个RDD,其中包含:

  • ({a:a1, b:b1, c:[1,2,3,4], d:d1}, x1)
  • ({a:a1, b:b1, c:[1,2,3,4], d:d1}, x2)
  • ({a:a1, b:b1, c:[1,2,3,4], d:d1}, x3)
  • ({a:a1, b:b1, c:[1,2,3,4], d:d1}, x4)

联接如下:

rdd2_tuple = rdd2.map(lambda line: line.items())
joined_rdd = flat_rdd1.join(rdd2_tuple).map(lambda x: x[1])

最后,您需要做的只是groupByKey获取({a:a1, b:b1, c:[1,2,3,4], d:d1}, [x1, x2, x3, x4])

result = joined_rdd.groupByKey()