我们有一个master-> detail数据集,该数据集由API访问,而明细数据则存储在HDFS的Parquet文件中。
主数据包含所有详细信息,以标识存储我们要查找的每一行数据的确切文件。当用户查询索引时,他们会收到返回的索引结果,通常分布在20k行左右的指针500个文件,每个行键将返回1个或更多行;通常,像这样的查询将为单个行键返回数千行。
环境:带有Python 3.6的PySpark 2.3.0
因为我们确切知道每个数据点位于哪个文件中,所以我一直在使用binaryFiles
来读取各个Parquet文件,并将(文件名,字节)以及索引结果一起传递给映射器,广播给所有执行者。
# indexdf is the Pandas dataframe containing the index results, broadcast to all executors.
brdcst = sc.broadcast(indexdf)
sc.binaryFiles(",".join(pfileobj)).map(lambda x: self.processFile(x, brdcst)).collect()
此代码对于小文件来说效果很好,但是当文件变大时,返回结果时我要么超过2GB的Spark shuffle限制,要么超过Pickling最大可序列化的大小限制。
我的Parquet行组具有行键的统计信息,因此,如果我可以基于Parquet行组进行映射,则类似于binaryFiles
,但具有(filename, rowgroup_stats, rowgroup_data)
这样的数据集(大约),我想我会克服所有这些问题,并获得更好的启动并行化。
我应该考虑的想法或新方向?
在该项目开始时,我确实尝试将每个文件分别加载到Spark SQL中并进行联接,但是由于我没有跨文件并行化,所以它的速度很慢。我还尝试将所有文件加载到单个Spark SQL Dataframe中并加入,但是这项工作花费了10倍以上的时间,因为我失去了知道数据在哪里的优势,而不得不扫描整个数据帧。