我正在尝试使用现有表中的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小时)。
有用的信息:
我有~6名工人。通过分析表格的分区数量,我得到:11433
。
我不确定分区/工人比例是否合理。
我正在使用Scala运行Spark 2.1.0。
我试过了:
删除.limit()
部分。
将frac
更改为1.0
,0.1
等
问题:如何让它更快?
最佳,
答案 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()