下面的Scala方法返回Array
的k个最近邻点:
def getNearestNeighbours(distances: Array[((String, String), Double)], k: Int, label: String) = { //| label: String)List[((String, String), Double)]
distances.filter(v => v._1._1.equals(label) || v._1._2.equals(label)).sortBy(_._2).take(k)
}
我想并行运行此功能。我可以尝试将Array
转换为RDD
但类型RDD
不支持函数.sortBy(_._2).take(k)
有没有办法在Spark / Scala中模拟此方法?
一种可能的解决方案是修改方法,以便每次调用方法时RDD都转换为数组,但我认为这对于大型RDD来说计算成本很高? :
def getNearestNeighbours(distances: RDD[((String, String), Double)], k: Int, label: String) = { //| label: String)List[((String, String), Double)]
distances.collect.filter(v => v._1._1.equals(label) || v._1._2.equals(label)).sortBy(_._2).take(k)
}
答案 0 :(得分:2)
不要collect
RDD。它将所有数据提取到一台机器上。更改输入,使其按否定距离(RDD[Double, (String, String)]
)键入,然后使用RDD.top(k)
。
答案 1 :(得分:1)
RDD确实有sortByKey
方法,它通过第一个元素对对的RDD进行排序,因此如果您可以创建RDD[(Double, (String, String))]
而不是RDD[((String, String), Double)]
(或只是调用rdd.map(p => (p._2, p._1)
) ,你可以直接翻译算法。它也有take
,但文档说:
返回包含数据集的前n个元素的数组。请注意,这当前不是并行执行的。相反,驱动程序计算所有元素。
所以我不希望这个很好。
此外,如果数据适合一台机器,那么只使用Arrays(或并行集合)可能会更快。 Spark尽其所能来减少开销,但分布式排序无论如何都会有一些开销!
此外,如果您只需要n
元素,则对整个数组/ RDD /其他集合进行排序是一个坏主意(同样,尤其是在您想要使用Spark的情况下)。您需要一个类似于Worst-case O(n) algorithm for doing k-selection或In an integer array with N elements , find the minimum k elements?中所述的选择算法。不幸的是,它们在Scala标准库或Spark(我知道)中都不可用。