如何找到距离最小的RDD

时间:2018-04-19 18:33:20

标签: scala apache-spark rdd analysis

我创建了这种类型的RDD:

RDD[(Long, Iterable[(String, Double)])]

这里第一个长参数是map中原始点的ID,第二个String参数是另一个点的id,它以一种固定数据集的String格式表示。第三个参数Double是两点之间的距离。

现在,我想找到给定点的最小距离点。所以,我想将此RDD转换为RDD[(Long, (String, Double))]。所以,我将拥有最接近给定点数的所有点。

我目前的输出是这样的

(4516831,CompactBuffer((POI1,2632.0690038389157), (POI2,2632.0690038389157), (POI3,666.9416656643995), (POI4,1450.3241112528403)))
(4516915,CompactBuffer((POI1,2632.0690038389157), (POI2,2632.0690038389157), (POI3,666.9416656643995), (POI4,1450.3241112528403)))

我试图编写的代码就是这个。

`
// groupData returns output in the format RDD[(Long, (String, Double))]
val combinedData = groupData(dataRdd, poiRdd)
  .groupByKey()
  .map(row => {
    var min:Double = 9999999
    for(value <- row._2) yield
      if (value._2 < min) {
        min = value._2
      } else min
  (row._1, row._2.filter(r => r._2 == min))
  }).foreach(println)
// output like this: (4516915,List((POI3,666.9416656643995)))`

上面的代码可以按照要求正常工作,但我认为这真的很糟糕,尤其是我按照自己的意愿返回输出的最后一行。我在那里再次过滤。 肯定有更好的办法。 我怎样才能做到这一点?如果问题含糊不清,我很抱歉。

感谢。

1 个答案:

答案 0 :(得分:0)

我认为您的样本输入数据是来自groupByKey的中间数据。如果是这样,让我们​​说你的原始RDD如下:

val rdd = sc.parallelize(Seq(
  (4516831, ("POI1", 2632.0690038389157)),
  (4516831, ("POI2", 2632.0690038389157)),
  (4516831, ("POI3", 666.9416656643995)),
  (4516831, ("POI4", 1450.3241112528403)),
  (4516915, ("POI1", 2632.0690038389157)),
  (4516915, ("POI2", 2632.0690038389157)),
  (4516915, ("POI3", 666.9416656643995)),
  (4516915, ("POI4", 1450.3241112528403))
))

val groupedRDD = rdd.groupByKey
// groupedRDD: org.apache.spark.rdd.RDD[(Int, Iterable[(String, Double)])] = ...

然后groupedRDD应该与您的示例输入数据具有完全相同的数据。

然后,您可以使用mapValues处理分组的RDD reduce以捕获最小值,并根据您的输出要求将缩小的结果包装在List中:

val resultRDD1 = groupedRDD.mapValues( _.reduce{
    (acc, x) => if (x._2 < acc._2) x else acc
  }).map{ case (k, v) => (k, List(v))}

resultRDD1.collect
// res1: Array[(Int, List[(String, Double)])] = Array(
//   (4516915,List((POI3,666.9416656643995))), (4516831,List((POI3,666.9416656643995)))
// )

但是,如果您只使用原始RDD数据,而不是使用groupByKey,则使用性能更高的reduceByKey,效果会更高效,如下所示:

val resultRDD2 = rdd.reduceByKey(
    (acc, x) => if (x._2 < acc._2) x else acc
  ).map{ case (k, v) => (k, List(v))}

resultRDD2.collect
// res2: Array[(Int, List[(String, Double)])] = Array(
//   (4516915,List((POI3,666.9416656643995))), (4516831,List((POI3,666.9416656643995)))
// )