Scala 火花采样太慢

Scala 火花采样太慢,scala,performance,apache-spark,random,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) .

我试图使用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

  • 问题:我怎样才能让它更快


    最好的是,

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

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

    否则,除了扩展集群之外,您对此无能为力



    *

    您可以先对分区进行采样,然后从分区中进行采样。像这样,您不需要进行完整的表扫描,但只有在分区本身是随机的情况下才有效。好的,您需要使用RDDAPI来实现这一点。这可能是这样的(插入数字以匹配所需的样本数):


    @user6910411,你介意在你的声明中添加一个链接吗?可能:@monteiro我不确定我是否理解你的要求。您是否认为该声明是错误的,水库取样确实解决了问题?如果答案是肯定的,则不是。水库采样解决了内存复杂性的问题,这在这里并不是一个问题。您面临的问题是时间复杂性。不管分数有多小,我们仍然扫描所有数据点。如果我们对单个记录进行有效的随机访问(我们没有这样做,主要是因为我们对类似流的数据进行操作,使用大型文件系统块,等等),它可能会得到改进。我对你的说法提出了一个错误的参考,即抽样是O(N)。我恳请你提及那份声明,以便人们可以在其他地方核实。
    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()