如何使用spark / scala在RDD中获取当前位置前的平均值

时间:2017-06-06 02:11:18

标签: scala apache-spark apache-spark-sql

我有RDD,我想在RDD中获取当前位置(包括当前位置)前面的平均值 例如:

inputRDD:
1,  2,   3,  4,   5,  6,   7,  8

output:
1,  1.5, 2,  2.5, 3,  3.5, 4,  4.5

这是我的尝试:

val rdd=sc.parallelize(List(1,2,3,4,5,6,7,8),4)
    var sum=0.0
    var index=0.0
    val partition=rdd.getNumPartitions
    rdd.zipWithIndex().collect().foreach(println)
    rdd.zipWithIndex().sortBy(x=>{x._2},true,1).mapPartitions(ite=>{
      var result=new ArrayBuffer[Tuple2[Double,Long]]()
      while (ite.hasNext){
        val iteNext=ite.next()
        sum+=iteNext._1
        index+=1
        var avg:Double=sum/index
        result.append((avg,iteNext._2))
      }
      result.toIterator
    }).sortBy(x=>{x._2},true,partition).map(x=>{x._1}).collect().foreach(println)

我必须repartition到1然后用数组计算它,它效率很低。

有没有在4个分区中使用数组的清洁解决方案?

2 个答案:

答案 0 :(得分:0)

更简单的解决方案是使用Spark-SQL。 我在这里计算每一行的平均值

val df = sc.parallelize(List(1,2,3,4,5,6,7,8)).toDF("col1")

df.createOrReplaceTempView("table1")

val result = spark.sql("""SELECT col1, sum(col1) over(order by col1 asc)/row_number() over(order by col1 asc) as avg FROM table1""")

或者如果您想使用DataFrames API。

import org.apache.spark.sql.expressions._
val result = df
 .withColumn("csum", sum($"col1").over(Window.orderBy($"col1")))
 .withColumn("rownum", row_number().over(Window.orderBy($"col1")))
 .withColumn("avg", $"csum"/$"rownum")
 .select("col1","avg")

<强>输出

result.show()

+----+---+
|col1|avg|
+----+---+
|   1|1.0|
|   2|1.5|
|   3|2.0|
|   4|2.5|
|   5|3.0|
|   6|3.5|
|   7|4.0|
|   8|4.5|
+----+---+

答案 1 :(得分:0)

抱歉,我不使用Scala,希望你能读懂它

df = spark.createDataFrame(map(lambda x: (x,), range(1, 9)), ['val'])
df = df.withColumn('spec_avg',
                   f.avg('val').over(Window().orderBy('val').rowsBetween(start=Window.unboundedPreceding, end=0)))