Python 在pyspark中加载大于内存的hdf5文件
我有一个大文件(比如20GB)以HDF5格式存储。该文件基本上是一组随时间演化的三维坐标(分子模拟轨迹)。这基本上是一个形状数组Python 在pyspark中加载大于内存的hdf5文件,python,apache-spark,hdf5,pyspark,Python,Apache Spark,Hdf5,Pyspark,我有一个大文件(比如20GB)以HDF5格式存储。该文件基本上是一组随时间演化的三维坐标(分子模拟轨迹)。这基本上是一个形状数组(8000(帧)、50000(粒子)、3(坐标)) 在常规python中,我只需使用forh5py或pytables加载hdf5数据文件,并像加载numpy一样对数据文件进行索引(库延迟加载它需要的任何数据) 但是,如果我尝试使用SparkContext.parallelize在Spark中加载此文件,它显然会阻塞内存: sc.parallelize(data, 10)
(8000(帧)、50000(粒子)、3(坐标))
在常规python中,我只需使用forh5py
或pytables
加载hdf5数据文件,并像加载numpy一样对数据文件进行索引(库延迟加载它需要的任何数据)
但是,如果我尝试使用SparkContext.parallelize在Spark中加载此文件,它显然会阻塞内存:
sc.parallelize(data, 10)
我如何处理这个问题?大型阵列是否有首选的数据格式?我可以在不经过内存的情况下将rdd写入磁盘吗?Spark(和Hadoop)不支持读取部分HDF5二进制文件。(我怀疑这是因为HDF5是用于存储文档的容器格式,它允许为文档指定树状层次结构)
但如果您需要从本地磁盘读取文件,使用Spark是可行的,尤其是当您知道HDF5文件的内部结构时
这里是一个-它假设您将运行本地spark作业,并且您预先知道HDF5数据集“/mydata”由100个块组成
h5file_path="/absolute/path/to/file"
def readchunk(v):
empty = h5.File(h5file_path)
return empty['/mydata'][v,:]
foo = sc.parallelize(range(0,100)).map(lambda v: readchunk(v))
foo.count()
更进一步,您可以使用f5['/mydata']修改程序以检测块的数量。shape[0]
下一步是迭代多个数据集(可以使用f5.keys()
列出数据集)
还有一些描述类似方法的例子
同样的方法也适用于分布式集群,但效率很低。h5py要求将文件导入本地文件系统。因此,这可以通过几种方式实现:将文件复制到所有工作人员,并将其保存在工作人员磁盘上的同一位置;或者将文件放入HDFS并使用fusefs挂载HDFS,以便工作人员可以访问该文件。这两种方法都有一些效率低下的地方,但对于临时任务来说应该足够好了
以下是优化版本,每个执行器只打开h5一次:
h5file_path="/absolute/path/to/file"
_h5file = None
def readchunk(v):
# code below will be executed on executor - in another python process on remote server
# original value for _h5file (None) is sent from driver
# and on executor is updated to h5.File object when the `readchunk` is called for the first time
global _h5file
if _h5file is None:
_h5file = h5.File(h5file_path)
return _h5file['/mydata'][v,:]
foo = sc.parallelize(range(0,100)).map(lambda v: readchunk(v))
foo.count()
我对hdf5不太熟悉,但可以逐行阅读吗?如果是这样,您可以读取sc.textFile(“hdf5_文件”)来读取该文件,然后使用某种映射函数对每个文件进行解码row@anant不幸的是,这是一种二进制格式(有时是压缩格式),我认为不可能逐行阅读。这是一种很好的解决问题的方法!但是为什么不将h5.File(h5file\u路径)移到readchunk()函数之外呢?因为hdf5文件在映射过程中被多次打开。@这是一个很好的观点-因为脚本正在为每个块打开相同的文件。但在远程执行器上执行map函数时,必须小心执行。此外,pyspark将无法序列化h5.File对象。所以您需要一些只打开h5一次并将其保存在全局变量中的惰性代码。如果您在编写此类代码时需要帮助,请告诉我。@vvladymyrov谢谢!我确实需要一些帮助来解决这个问题。我在pyspark中遇到了类似的序列化问题。我的代码类似于读取全局变量中的hdf5.file和hdf5数据集,然后传递给read chunk方法。但在pyspark映射阶段,它返回类似“h5py/h5py/objects.c:uu cinit_uz()正好接受1个位置参数(给定0)”的错误。hdf5数据集似乎不支持不先打开文件的直接并行I/O。