在Apache Zeppelin笔记本中用PySpark序列化Gensim语料库的路径问题
问题分析与解决方案
首先得明确两个核心问题:Gensim的文件操作是基于本地文件系统的,而PySpark集群运行时,Executor的本地文件系统和HDFS、你客户端的本地文件系统是完全隔离的,这就是你遇到路径问题的根源。
为什么会出现这些现象?
- 当你指定
/my/existing/hadoop/path时:Gensim会去当前运行代码的Executor节点的本地文件系统找这个路径,而不是HDFS。如果Executor节点上没有这个本地路径,就会报"No such file or directory"错误。 - 当你写
corpus.mm或/tmp/corpus.mm时:文件确实生成了,但它是在Executor节点的本地文件系统里,不是HDFS的/tmp,也不是你客户端机器的/tmp。所以你用hadoop fs -ls /tmp或者本地查看/tmp都找不到,得去对应的Executor节点上查看。
正确的处理方式
方式一:先写本地临时文件,再上传到HDFS
利用PySpark可以调用HDFS命令的特性,先在Executor本地生成文件,再上传到目标HDFS路径:
from gensim import corpora import subprocess import tempfile import os # 1. 在Executor本地创建临时文件并写入语料 corpus = [[(0,0), (1,2)]] with tempfile.NamedTemporaryFile(mode='wb', delete=False) as tmp_file: corpora.MmCorpus.serialize(tmp_file.name, corpus) # 2. 上传到HDFS指定路径(替换成你的目标路径) hdfs_target_path = "/my/existing/hadoop/path/corpus.mm" subprocess.run(["hadoop", "fs", "-put", "-f", tmp_file.name, hdfs_target_path]) # 3. 清理Executor本地的临时文件 os.unlink(tmp_file.name)
注意:
-f参数是为了覆盖已存在的文件,如果不需要可以去掉。
方式二:直接用HDFS Python客户端写入(更优雅)
使用支持HDFS的Python库(比如pyarrow),直接打开HDFS文件对象传给Gensim的serialize方法(Gensim支持传入文件对象,不只是本地路径):
from gensim import corpora import pyarrow.hdfs # 连接HDFS(替换成你的NameNode主机和端口,默认端口是9000) hdfs = pyarrow.hdfs.HadoopFileSystem(host="your_namenode_host", port=9000) corpus = [[(0,0), (1,2)]] hdfs_target_path = "/my/existing/hadoop/path/corpus.mm" # 直接写入HDFS with hdfs.open(hdfs_target_path, 'wb') as hdfs_file: corpora.MmCorpus.serialize(hdfs_file, corpus)
前提:需要确保所有Executor节点都安装了
pyarrow库,并且NameNode地址和端口正确。
补充:关于Zeppelin中直接写corpus.mm的文件位置
如果你运行corpora.MmCorpus.serialize("corpus.mm", corpus)成功了,这个文件会保存在Zeppelin服务器进程所在节点的当前工作目录(一般是Zeppelin的安装目录或者运行目录),你可以登录到Zeppelin所在节点去查找,或者通过Zeppelin的文件管理功能(如果开启的话)查看。
内容的提问来源于stack exchange,提问作者Miroslav Stola
相关产品推荐
相关产品推荐

