如何得到两个RDD的交集[(String,Iterable [String])]

时间:2018-06-01 22:49:02

标签: scala apache-spark rdd

数据由两列组成

A B
A C
A D
B A
B C
B D
B E
C A
C B
C D
C E
D A
D B
D C
D E
E B
E C
E D

在第一行中,将其视为A是B的朋友等。 我如何找到他们共同的朋友?

(A,B) -> (C D)

含义A和B有共同的朋友C和D.我和groupByKey一样接近以下结果。

(B,CompactBuffer(A, C, D, E))
(A,CompactBuffer(B, C, D))
(C,CompactBuffer(A, B, D, E))
(E,CompactBuffer(B, C, D))
(D,CompactBuffer(A, B, C, E))

代码:

val rdd: RDD[String] = spark.sparkContext.textFile("twocols.txt")
val splitrdd: RDD[(String, String)] = rdd.map { s =>
  var str = s.split(" ")
  new Tuple2(str(0), str(1))
}
val group: RDD[(String, Iterable[String])] = splitrdd.groupByKey()
group.foreach(println)

4 个答案:

答案 0 :(得分:1)

首先swap元素:

val swapped = splitRDD.map(_.swap)

然后自我加入并swap回复:

val shared =  swapped.join(swapped).map(_.swap)

最后过滤掉重复项(如果需要)和groupByKey

shared.filter { case ((x, y), _) => x < y }.groupByKey

答案 1 :(得分:0)

这只是一次丑陋的尝试:

假设您已将两列转换为Array[Array[String]](或List[List[String]],它实际上是相同的),比如说

val pairs=Array(
Array("A","B"),
Array("A","C"),
Array("A","D"),
Array("B","A"),
Array("B","C"),
Array("B","D"),
Array("B","E"),
Array("C","A"),
Array("C","B"),
Array("C","D"),
Array("C","E"),
Array("D","A"),
Array("D","B"),
Array("D","C"),
Array("D","E"),
Array("E","B"),
Array("E","C"),
Array("E","D")
)

定义您想要找到他们共同朋友的群组:

val group=Array("C","D")

以下内容将为您小组中的每位成员找到朋友

val friendsByMemberOfGroup=group.map(
i => pairs.filter(x=> x(1) contains i)
.map(x=>x(0))
)

例如,pairs.filter(x=>x(1) contains "C").map(x=>x(0))会返回"C"的朋友,其中"C"来自第二列,其朋友来自第一列:

scala> pairs.filter(x=> x(1) contains "C").map(x=>x(0))
res212: Array[String] = Array(A, B, D, E)

以下循环将找到您小组中所有成员的共同朋友

var commonFriendsOfGroup=friendsByMemberOfGroup(0).toSet
for(i <- 1 to friendsByMemberOfGroup.size-1){
commonFriendsOfGroup=
commonFriendsOfGroup.intersect(friendsByMemberOfGroup(i).toSet)
}

所以你得到了

scala> commonFriendsOfGroup.toArray
res228: Array[String] = Array(A, B, E)

如果您将论坛更改为val group=Array("A","B","E")并应用之前的行,那么您将获得

scala> commonFriendsOfGroup.toArray
res230: Array[String] = Array(C, D)

答案 2 :(得分:-1)

继续你离开的地方:

val group: RDD[(String, Iterable[String])] = splitrdd.groupByKey()
val group_map = group.collectAsMap
val common_friends = group
  .flatMap{case (x, friends) => 
    friends.map{y => 
      ((x,y),group_map.get(y).get.toSet.intersect(friends.toSet))
    }
  }

scala> common_friends.foreach(println)
((B,A),Set(C, D))
((B,C),Set(A, D, E))
((B,D),Set(A, C, E))
((B,E),Set(C, D))
((D,A),Set(B, C))
((D,B),Set(A, C, E))
((D,C),Set(A, B, E))
((D,E),Set(B, C))
((A,B),Set(C, D))
((A,C),Set(B, D))
((A,D),Set(B, C))
((C,A),Set(B, D))
((C,B),Set(A, D, E))
((C,D),Set(A, B, E))
((C,E),Set(B, D))
((E,B),Set(C, D))
((E,C),Set(B, D))
((E,D),Set(B, C))

注意:这假设您的数据在两个方向上都有关系,例如:(A B和B A)。如果不是这样,您需要添加一些代码来处理group_map.get(y)可能返回None的事实。

答案 3 :(得分:-1)

所以我最终在客户端这样做了。不要这样做

val arr: Array[(String, Iterable[String])] = group.collect()
//arr.foreach(println)
var arr2 = scala.collection.mutable.Set[((String, String), List[String])]()
for (i <- arr)
  for (j <- arr)
    if (i != j) {
      val s1 = i._2.toSet
      val s2 = j._2.toSet
      val s3 = s1.intersect(s2).toList
      //println(s3)
      val pair = if (i._1 < j._1) (i._1, j._1) else (j._1, i._1)
      arr2 += ((pair, s3))
    }

arr2.foreach(println)

结果是

((B,E),List(C, D))
((A,C),List(B, D))
((A,B),List(C, D))
((A,D),List(B, C))
((B,D),List(A, C, E))
((C,D),List(A, B, E))
((B,C),List(A, D, E))
((C,E),List(B, D))
((D,E),List(B, C))
((A,E),List(B, C, D))

我想知道我是否可以使用Spark中的转换来做到这一点。