在Apache-Spark中使用统计方法完成表时,如何提高性能?

时间:2016-05-04 21:47:10

标签: performance scala apache-spark

我有一个包含10个字段和5000行的数据集。我想用Spark with Scala中的一些统计方法来完成这个数据集。我填充了一个字段的空单元格,其中包含该字段的平均值,如果它由连续值组成,并且我将最常用的值放在字段中,如果它由离散值组成。这是我的代码:

for(col <- cols){

  val datacount = table.select(col).rdd.map(r => r(0)).filter(_ == null).count()      

  if(datacount > 0)
  {      
    if (continuous_lst contains col)               // put mean of data to null values
    {             
      var avg = table.select(mean(col)).first()(0).asInstanceOf[Double]    
      df = df.na.fill(avg, Seq(col))             
    }

    else if(discrete_lst contains col)            // put most frequent categorical value to null values
    {
      val group_df = df.groupBy(col).count()  
      val sorted = group_df.orderBy(desc("count")).take(1)

      val most_frequent = sorted.map(t => t(0))
      val most_frequent_ = most_frequent(0).toString.toDouble.toInt

      val type__ = ctype.filter(t => t._1 == col)
      val type_ = type__.map(t => t._2)

      df = df.na.fill(most_frequent_, Seq(col))  
      }

    }
  }

问题是此代码对此数据的运行速度非常慢。我将spark-submitexecutor memory 8G参数一起使用。在将数据发送到此函数之前,我使用repartition(4)参数。

我应该使用更大尺寸的数据集。那么我怎样才能加快这段代码的速度呢?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

这是一个建议:

import org.apache.spark.sql.funcitons._

def most_frequent(df: DataFrame, col: Column) = {
  df.select(col).map { case Row(colVal) => (colVal, 1)  } 
    .reduceByKey(_ + _)
    .reduce({case ((val1, cnt1), (val2, cnt2)) => if (cnt1 > cnt2) (val1, cnt1) else (val2, cnt2)})._1
}

val new_continuous_cols = continuous_lst.map {
  col => coalesce(col, mean(col)).as(col.toString)
}.toArray

val new_discrete_cols = discrete_lst.map {
  col => coalesce(col, lit(most_frequent(table, col)).as(col.toString))
}.toArray

val all_new_cols = new_continuous_cols ++ new_discrete_cols
val newDF = table.select(all_new_cols: _*)

<强>考虑:

  • 我认为continuous_lstdiscrete_lstColumn的列表。如果它们是String的列表,那么这个想法是相同的,但有些调整是必要的;
  • 请注意,我使用mapreduce来计算列的最常用值。在某些情况下,这可能比分组和聚合更好。 (也许这里有改进的余地,一次计算所有离散列的最常见值?);
  • 此外,我使用coalesce替换空值,而不是fill。这也可能导致一些改进。 (有关scaladoc API)中coalesce功能的更多信息;
  • 我现在无法测试,所以可能会遗漏一些我没有看到的东西。