如何优化下面的火花代码(scala)?

时间:2016-11-29 00:17:21

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

我有一些巨大的文件(19GB,40GB等)。我需要对这些文件执行以下算法:

  1. 阅读文件
  2. 根据1列
  3. 对其进行排序
  4. 获取前70%的数据:

    a)获取列子集的所有不同记录  b)将其写入培训档案

  5. 获取最后30%的数据:

    a)获取列子集

    的所有不同记录

    b)将其写入测试文件

  6. 我尝试在spark中运行以下代码(使用Scala)。

    import scala.collection.mutable.ListBuffer
    
    import java.io.FileWriter
    
    import org.apache.spark.sql.functions.year
    
        val offers = sqlContext.read
        .format("com.databricks.spark.csv")
        .option("header", "true") // Use first line of all files as header
        .option("inferSchema", "true") // Automatically infer data types
        .option("delimiter", ",")
        .load("input.txt")
        val csvOuterJoin = offers.orderBy("utcDate")
        val trainDF = csvOuterJoin.limit((csvOuterJoin.count*.7).toInt)
        val maxTimeTrain = trainDF.agg(max("utcDate"))
        val maxtimeStamp = maxTimeTrain.collect()(0).getTimestamp(0)
        val testDF = csvOuterJoin.filter(csvOuterJoin("utcDate") > maxtimeStamp)    
        val inputTrain = trainDF.select("offerIdClicks","userIdClicks","userIdOffers","offerIdOffers").distinct
        val inputTest = testDF.select("offerIdClicks","userIdClicks","userIdOffers","offerIdOffers").distinct
        inputTrain.rdd.coalesce(1,false).saveAsTextFile("train.csv")
        inputTest.rdd.coalesce(1,false).saveAsTextFile("test.csv")   
    

    这就是我启动spark-shell的方式:

    ./bin/spark-shell --packages com.databricks:spark-csv_2.11:1.4.0 --total-executor-cores 70 --executor-memory 10G --driver-memory 20G
    

    我在分布式集群上执行此代码,其中包含1个主服务器和许多从服务器,每个服务器都有足够的RAM。截至目前,这段代码最终占用了大量内存,并且我得到了java堆空间问题。

    有没有办法优化上面的代码(最好是火花)?我非常感谢优化上述代码的任何最小帮助。

2 个答案:

答案 0 :(得分:2)

问题是你根本不分发。来源就在这里:

val csvOuterJoin = offers.orderBy("utcDate")
val trainDF = csvOuterJoin.limit((csvOuterJoin.count*.7).toInt)

limit操作不适用于大规模操作,它会将所有记录移动到单个分区:

val df = spark.range(0, 10000, 1, 1000)
df.rdd.partitions.size
Int = 1000
// Take all records by limit
df.orderBy($"id").limit(10000).rdd.partitions.size
Int = 1

您可以使用RDD API:

val ordered = df.orderBy($"utcDate")
val cnt = df.count * 0.7

val train = spark.createDataFrame(ordered.rdd.zipWithIndex.filter {
  case (_, i) => i <= cnt 
}.map(_._1), ordered.schema)

val test = spark.createDataFrame(ordered.rdd.zipWithIndex.filter {
  case (_, i) => i > cnt 
}.map(_._1), ordered.schema)

答案 1 :(得分:1)

coalesce(1,false)表示将所有数据合并到一个分区中,即将40GB数据保存在一个节点的内存中。

永远不要试图通过coalesce(1,false)将所有数据都放在一个文件中。 相反,您应该只调用saveAsTextFile(因此输出看起来像part-00001,part00002等),然后将这些分区文件合并到外面。 合并操作取决于您的文件系统。如果是HDFS,您可以使用http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-common/FileSystemShell.html#getmerge