在pyspark中加载大于内存hdf5文件

时间:2015-06-23 17:50:39

标签: python apache-spark hdf5 pyspark

我有一个以HDF5格式存储的大文件(比如20 Gb)。该文件基本上是一组随时间演变的3D坐标(分子模拟轨迹)。这基本上是一个形状(8000 (frames), 50000 (particles), 3 (coordinates))

的数组

在常规python中,我只需使用for h5pypytables加载hdf5数据文件,并将数据文件编入索引,如果它是一个numpy(库懒惰地加载它需要的任何数据)。

但是,如果我尝试使用SparkContext.parallelize在Spark中加载此文件,它显然会阻塞内存:

sc.parallelize(data, 10)

我该如何处理这个问题?是否有大型数组的首选数据格式?我可以将rdd写入磁盘而不通过内存吗?

1 个答案:

答案 0 :(得分:4)

Spark(和Hadoop)不支持读取部分HDF5二进制文件。 (我怀疑其原因是HDF5是一种用于存储文档的容器格式,它允许为文档指定树状层次结构)。

但是如果你需要从本地磁盘读取文件 - 特别是如果你知道你的HDF5文件的内部结构,它可以用于Spark。

这是example - 它假设您将运行本地火花作业,并且您事先知道您的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()列出数据集。)

还有another article "From HDF5 Datasets to Apache Spark RDDs"描述了类似的方法。

同样的方法可以在分布式集群上运行,但效率很低。 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()