Python 在pyspark中加载大于内存的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)

我有一个大文件(比如20GB)以HDF5格式存储。该文件基本上是一组随时间演化的三维坐标(分子模拟轨迹)。这基本上是一个形状数组
(8000(帧)、50000(粒子)、3(坐标))

在常规python中,我只需使用for
h5py
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。