我有一些巨大的文件(19GB,40GB等)。我需要对这些文件执行以下算法:
获取前70%的数据:
a)获取列子集的所有不同记录 b)将其写入培训档案
获取最后30%的数据:
a)获取列子集
的所有不同记录b)将其写入测试文件
我尝试在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堆空间问题。
有没有办法优化上面的代码(最好是火花)?我非常感谢优化上述代码的任何最小帮助。
答案 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