使用Spark中的Scala加入两个RDD

时间:2017-02-09 14:41:07

标签: arrays scala join apache-spark

我正在尝试在Spark上实现Local Outlier Factor。所以我从文件中读取了一组点,然后为每个点找到N个最近的邻居。每个点都有一个使用zipWithIndex()命令给它的索引

所以现在我有两个RDD 首先

RDD[(Index:Long, Array[(NeighborIndex:Long, Distance:Double)])]

其中Long表示其索引,并且Array由其N个最近邻居组成,Long表示这些邻居的Index位置,Double表示距离给定点的距离

第二

RDD[(Index:Long,LocalReachabilityDensity:Double)]

此处,Long再次表示给定点的索引,Double表示其Local Reachability密度

我想要的是一个RDD,它包含所有点,以及它们的N个最近邻居的数组及其本地可达性密度

RDD[(Index:Long, Array[(NeighborIndex:Long,LocalReachabilityDensity:Double)])]

所以基本上在这里,Long将表示一个点的索引,并且该数组将是其N个最接近的邻居,其索引值和Local Reachability密度。

根据我的理解,我需要在第一个RDD上运行一个映射,然后将其数组中的值与包含Local Reachability密度的第二个RDD连接起来,以获得其所有给定索引的Local Reachability密度N个邻居。但我不知道如何实现这一目标。如果有人可以帮助我,那就太棒了

1 个答案:

答案 0 :(得分:1)

假设:

val rdd1: RDD[(index: Long, Array[(neighborIndex: Long, distance: Double)])] = ...
val rdd2: RDD[(index: Long, localReachabilityDensity: Double)] = ...

我真的不喜欢使用Scala的Array。我也不喜欢你的抽象是交叉目的;换句话说,index中的rdd2被隐藏在rdd1中的各个条目中。这使得事情难以推理,并且还会引发Spark RDD API的限制,在转换第一个RDD时,您无法访问第二个RDD。我相信你应该重写当前的工作,以便更容易地使用抽象工作。

但如果你必须:

val flipped = rdd1.map { 
  case (index, array) => 
    array.map {
      case (neighborIndex, distance) => (neighborIndex, (index, distance))
    }.elements.toVector
}.flatMap(identity)
 .groupBy(_._1)
val result = flipped.join(rdd2).mapValues {
   case (indexDistances, localReachabilityDensity) => 
      indexDistances.map {
         case (index, _) => (index, localReachabilityDensity)
      }    
}

基本想法是将rdd1翻转为“提取”neighborIndex值到顶层作为PairRDD的键,然后允许我执行{{1}与join一起使用。并将rdd2替换为Array。一旦你对相同的索引进行连接,组合事物会容易得多。

请注意,这不是我的头脑,可能并不完美。这个想法不是给你一个复制粘贴的解决方案,而是建议一个不同的方向。