我怎样才能避免针对KNN搜索的循环?

时间:2015-06-26 12:08:59

标签: scala apache-spark rdd

我的目标是让每个数据点的k个最近邻居。我想避免使用带有查询的for循环并在每个rdd_distance点上同时使用其他内容,但我无法弄清楚如何执行此操作。

parsedData = RDD[Object]
//Object have an id and a vector as attribute
//sqdist1 output is a Double

var rdd_distance = parsedData.cartesian(parsedData)
  .flatMap { case (x,y) =>
    if(x.get_id != y.get_id) 
      Some((x.get_id,(y.get_id,sqdist1(x.get_vector,y.get_vector))))
    else None
  }
for(ind1 <- 1 to size) {
  val ind2 = ind1.toString
  val tab1 = rdd_distance.lookup(ind2)
  val rdd_knn0 = sc.parallelize(tab1)
  val tab_knn = rdd_knn0.takeOrdered(k)(Ordering[(Double)].on(x=>x._2))
}

如果不使用带循环的for循环,是否可以这样做?

1 个答案:

答案 0 :(得分:2)

此代码解决了您的问题(但parsedData的数量很大时效率低下。)

  rdd_distance.groupByKey().map {
    case (x, iterable) =>
      x -> iterable.toSeq.sortBy(_._2).take(k)
  }

所以这是更合适的解决方案。

import org.apache.spark.mllib.rdd.MLPairRDDFunctions._    

rdd_distance.topByKey(k)(Ordering.by(-_._2)) // because smaller is better.

请注意,此代码包含Spark 1.4.0。如果您使用的是早期版本,请使用此代码https://github.com/apache/spark/blob/master/mllib/src/main/scala/org/apache/spark/mllib/rdd/MLPairRDDFunctions.scala

topBykey的想法是将BoundedPriorityQueueaggregateByKey一起使用,保留前k项。