是否存在查看相邻元素的RDD转换函数?

时间:2015-07-21 11:38:16

标签: java apache-spark

有人知道在转换过程中是否有办法查看已排序的RDD中的相邻元素?我知道我可以收集然后执行下面示例中的操作,但是它会破坏分布式系统的目的,并且我试图利用它分布的事实。

示例:

(字符串名称,int val)的RDD映射到(字符串名称,int val,int diff)的RDD

这样:

name | val     becomes ->      name | val | diff (current - prior)
a    | 3                       a    | 3   | 3
b    | 6                       b    | 6   | 3
c    | 4                       c    | 4   | -2
d    | 20                      d    | 20  | 16

1 个答案:

答案 0 :(得分:0)

可能最有效的方法最简单的方法是将RDD转换为数据帧并使用滞后:

case class NameValue(name: String, value: Int)
val rdd = sc.parallelize(
    NameValue("a", 3) ::  NameValue("b", 6) :: 
    NameValue("c", 4) ::  NameValue("d", 20) :: Nil)

val df = sqlContext.createDataFrame(rdd)
df.registerTempTable("df")
sqlContext.sql("""SELECT name, value,
                  value - lag(value) OVER (ORDER BY name, value) lag
                  FROM df""").show

不幸的是,此时没有PARTITION BY子句的窗口函数会将所有数据移动到单个分区,因此如果您有大型数据集,它会特别有用。

使用低级别操作,您可以使用zipWithIndex,然后使用flatMapgroupByKey

case class NameValueWithLag(name: String, value: Int, lag: Int)
val cnt = rdd.count() - 1

rdd.
    zipWithIndex.
    flatMap{case (x, i) => (0 to 1).map(lag => (i - lag, (i, x)))}.
    groupByKey.
    filter{ case (k, v) => k != cnt}.
    values.
    map(vals => {
        val sorted = vals.toArray.sortBy(_._1).map(_._2)
        if (sorted.length == 1) {
            NameValueWithLag(sorted(0).name, sorted(0).value, sorted(0).value)
        } else {
            NameValueWithLag(
               sorted(1).name, sorted(1).value,
               sorted(1).value - sorted(0).value
            )
        }
    })

编辑:

如果您不介意使用开发人员API,可以尝试RDDFunctions.sliding,但需要手动处理

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

val first = rdd.first match {
  case NameValue(name, value) => NameValueWithLag(name, value, value)
}

sc.parallelize(Seq(first)).union(rdd
  .sliding(2)
  .map(a => NameValueWithLag(a(1).name, a(1).value, a(1).value - a(0).value)))