【问题标题】:How to compare every element in the RDD with every other element in the RDD ?如何将 RDD 中的每个元素与 RDD 中的每个其他元素进行比较?
【发布时间】:2015-04-29 15:52:21
【问题描述】:

我正在尝试使用 spark 执行 K 最近邻搜索。

我有一个 RDD[Seq[Double]] 我打算返回一个 RDD[(Seq[Double],Seq[Seq[Double]])] 带有实际行和邻居列表

val out = data.map(row => {
    val neighbours = data.top(num = 3)(new Ordering[Seq[Double]] {
      override def compare(a:Seq[Double],b:Seq[Double]) = {
        euclideanDistance(a,row).compare(euclideanDistance(b,row))*(-1)
      }
    })
  (row,neighbours.toSeq)
})

它在 spark Submit 上给出以下错误

15/04/29 21:15:39 WARN TaskSetManager: Lost task 0.0 in stage 1.0 (TID 2, 192.168.1.7): org.apache.spark.SparkException: RDD transformations and actions can only be invoked by the driver, not inside of other transformations; for example, rdd1.map(x => rdd2.values.count() * x) is invalid because the values transformation and count action cannot be performed inside of the rdd1.map transformation. For more information, see SPARK-5063.

我知道嵌套 RDD 是不可能的,但是我如何执行这样的操作,我可以将 RDD 中的每个元素与 RDD 中的每个其他元素进行比较

【问题讨论】:

  • 如何比较RDD中的每个元素和RDD中的每个其他元素?
  • 您可以使用cartesian 方法生成所有可能对的RDD
  • 最近有一个问题与此非常相似,但我现在找不到...
  • 使用笛卡尔生成所有对。然后映射它以计算所有对之间的距离,第一个元素仍然是原始行值。 aggregateByKey,使用保持前“k”个最接近值的组合函数? (您可以在 combine 函数中包含欧几里得计算,这样会更快一些,但可能不太清楚)

标签: scala apache-spark nearest-neighbor


【解决方案1】:

应该这样做。

import org.apache.spark.SparkContext
import org.apache.spark.SparkContext._
import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD

val conf = new SparkConf().setAppName("spark-scratch").setMaster("local")
val sco= new SparkContext(conf)

// k is the number of nearest neighbors required 
val k = 3

// generate 5 rows of two-dimensional coordinates
val rows = List.fill(5)(List.fill(2)(Math.random))
val dataRDD = sco.parallelize(rows, 1)

// No need for the sqrt as we're just comparing them
def euclidean(a:List[Double], b:List[Double]) = 
 (a zip b) map {case (x:Double, y:Double) => (x-y)*(x-y)} sum

// get all pairs
val pairs = dataRDD.cartesian(dataRDD)

// case class to keep things a bit neater
// the neighbor, and its distance from the current point
case class Entry(neighbor: List[Double], dist:Double)

// map the second element to the element and distance from the first
val pairsWithDist = pairs.map {case (x, y) => (x, Entry(y, euclidean(x,y)))}

// merge a row of pairsWithDist with the ResultRow for this point
def mergeOne(u: List[Entry], v:Entry) = (v::u).sortBy{_.dist}.take(k)

// merge two results from different partitions
def mergeList(u: List[Entry], v:List[Entry]) = (u:::v).sortBy{_.dist}.take(k)

val nearestNeighbors = pairsWithDist
                      .aggregateByKey(List[Entry]())(mergeOne, mergeList)

【讨论】:

  • euclidean() 方法中的 reduce _ + _ 是什么?
  • 这是reduce{ (a, b) => a + b }的快捷方式。 lambda 表达式中的多个下划线表示不同的参数。
  • reduce +只是对map函数返回的list[Double]做求和操作
  • 所有正确,但当然如果我使用sum 会更清楚。更新
  • @Paul 谢谢你的回答。这是使用 spark 进行 K-Nearest Neighbor 查询的最有效方法,还是有任何其他方法可以优化?
猜你喜欢
  • 2013-06-06
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
  • 1970-01-01
  • 1970-01-01
  • 2021-02-05
  • 2020-07-03
相关资源
最近更新 更多