火花样本太慢了

时间:2018-04-24 14:17:53

标签: scala performance apache-spark random

我正在尝试使用现有表中的Scala执行一个简单的随机样本,其中包含大约100e6条记录。

import org.apache.spark.sql.SaveMode

val nSamples = 3e5.toInt
val frac = 1e-5
val table = spark.table("db_name.table_name").sample(false, frac).limit(nSamples)
(table
  .write
  .mode(SaveMode.Overwrite)
  .saveAsTable("db_name.new_name")
)

但这花了太长时间(根据我的估计约为5小时)。

有用的信息:

  1. 我有~6名工人。通过分析表格的分区数量,我得到:11433

  2. 我不确定分区/工人比例是否合理。

  3. 我正在使用Scala运行Spark 2.1.0。

  4. 我试过了:

    1. 删除.limit()部分。

    2. frac更改为1.00.1

    3. 问题:如何让它更快?

      最佳,

2 个答案:

答案 0 :(得分:3)

限制绝对值得删除,但真正的问题是采样需要完整的数据扫描。无论分数有多低,时间复杂度仍然是 O(N) *。

如果您不需要良好的统计属性,可以先尝试通过采样数据文件来限制首先加载的数据量,然后再从简化数据集中进行二次采样。如果数据均匀分布,这可能会相当有效。

否则除了扩展群集之外,你无能为力。

* How do simple random sampling and dataframe SAMPLE function work in Apache Spark (Scala)?

答案 1 :(得分:1)

您可以先对分区进行采样,然后从分区中进行采样。像这样,您不需要全表扫描,但只有在分区本身是随机的情况下才有效。 AFAIK您需要为此使用RDD API。这可能看起来像这样(插入数字以匹配您想要的样本数量):

val ds : Dataset[String] = ???

  val dsSampled = ds.rdd
  // take 1000 samples from every 10th partition
  .mapPartitionsWithIndex{case (i,rows) => if(i%10==0) scala.util.Random.shuffle(rows).take(1000) else Iterator.empty}
  .toDS()