繁体   English   中英

加入一个巨大而巨大的火花数据框

[英]Joining a large and a ginormous spark dataframe

我有两个数据帧,df1 有 600 万行,df2 有 10 亿行。

我尝试过标准的df1.join(df2,df1("id")<=>df2("id2")) ,但内存不足。

df1 太大,无法放入广播连接。

我什至尝试过布隆过滤器,但它也太大了,无法放入广播中,但仍然有用。

我尝试过的唯一不会出错的方法是将 df1 分成 300,000 个行块并在 foreach 循环中与 df2 连接。 但这比它可能需要的时间长一个数量级(可能是因为它太大而无法作为持久化,导致它重做分割到那个点)。 重新组合结果也需要一段时间。

你是如何解决这个问题的?

一些注意事项:

df1 是 df2 的子集。 df1=df2.where("fin<1").selectExpr("id as id2").distinct()我对 df2 中的所有行都感兴趣,这些行的 ID 曾经有一个 fin<1,这意味着我不能一步到位。

df2 中大约有 2 亿个唯一 ID。

以下是一些相关的火花设置:

spark.cores.max=1000
spark.executor.memory=15G
spark.akka.frameSize=1024
spark.shuffle.consolidateFiles=false
spark.task.cpus=1
spark.driver.cores=1
spark.executor.cores=1
spark.memory.fraction=0.5
spark.memory.storageFraction=0.3
spark.sql.shuffle.partitions=10000
spark.default.parallelism=10000

我得到的错误是:

16/03/11 04:36:07 ERROR LiveListenerBus: SparkListenerBus has already stopped! Dropping event SparkListenerTaskEnd(11,1,ResultTask,FetchFailed(BlockManagerId(68dcb91c-1b45-437d-ac47-8e8c1e4bc386-S199, mapr, 46487),3,176,4750,org.apache.spark.shuffle.FetchFailedException: java.io.FileNotFoundException: /tmp/mesos/work/slaves/68dcb91c-1b45-437d-ac47-8e8c1e4bc386-S199/frameworks/c754216b-bf80-4d84-97f1-2e907030365e-2545/executors/16/runs/5a5a01c5-205e-4380-94d3-7fa0f6421b85/blockmgr-ea345692-05bb-4f42-9ba1-7b93311fb9d4/0e/shuffle_3_340_0.index (No such file or directory)

Caused by: org.apache.spark.SparkException: Job aborted due to stage failure: Task 465 in stage 6.3 failed 4 times, most recent failure: Lost task 465.3 in stage 6.3 (TID 114448, mapr): java.lang.OutOfMemoryError: Direct buffer memory

我认为你有一个太大的分区问题(可能是由于更大的数据)你可以尝试一些方法:

  1. 尝试将spark.sql.shuffle.partitions定义为2048甚至更多(默认值为200)。 加入你的df-s时会有洗牌。 尝试使用此参数,以便更大数据/此参数的总体积约为64Mb-100Mb(取决于文件格式)。 通常,您应该在spark UI中看到每个任务(每个分区)处理“正常”数据量(最大64MB-100MB)

  2. 如果第一个不起作用我可以建议加入RDD api。 将您的df转换为RDD。 然后通过HashPartitioner(分区数)对两个RDD进行分区。 当我应该如前所述计算分区数时。

  3. 最近火花开发者添加了新的选项:你可以将巨大的表存入N个桶(即存储它为连接做好准备)。 存在的限制很少,但它可以完全消除混乱的巨大数据。 bucketBy仅受saveAsTable api支持而不保存。 在您获取数据并将其分解后,在下一次迭代中,您可以将此数据作为外部表加载,同时提供存储规范(请参阅https://docs.databricks.com/spark/latest/spark-sql/language-manual/ create-table.html

    CREATE TABLE ginormous --...在这里你必须指定模式USING PARQUET CLUSTERED BY(a,b,c)INTO N桶LOCATION'hdfs:// your-path'

然后,当您将巨型表加载为分段表时,可以加载大表并将其重新分配到相同数量的桶和相同列(df.repartition(N,a,b,c))

你可以尝试设置,spark.shuffle.memoryFraction = 0.0吗?

这将导致shuffle将所有内容溢出到磁盘,并且您永远不会收到OOM错误

如果符合您的要求,您也可以使用双程方法。 首先,重新分区数据并使用分区表(dataframe.write.partitionBy())持久化。 然后,在循环中串行连接子分区,“追加”到同一个最终结果表。

高效的pyspark加入

如果这种方法适合您,请告诉我。如果您有更好的选择加入两个大型数据框并希望共享,请告诉我。 :-)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM