我正在尝试在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个邻居。但我不知道如何实现这一目标。如果有人可以帮助我,那就太棒了
答案 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
。一旦你对相同的索引进行连接,组合事物会容易得多。
请注意,这不是我的头脑,可能并不完美。这个想法不是给你一个复制粘贴的解决方案,而是建议一个不同的方向。