我有一个以HDF5格式存储的大文件(比如20 Gb)。该文件基本上是一组随时间演变的3D坐标(分子模拟轨迹)。这基本上是一个形状(8000 (frames), 50000 (particles), 3 (coordinates))
在常规python中,我只需使用for h5py
或pytables
加载hdf5数据文件,并将数据文件编入索引,如果它是一个numpy(库懒惰地加载它需要的任何数据)。
但是,如果我尝试使用SparkContext.parallelize
在Spark中加载此文件,它显然会阻塞内存:
sc.parallelize(data, 10)
我该如何处理这个问题?是否有大型数组的首选数据格式?我可以将rdd写入磁盘而不通过内存吗?
答案 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()