Python本地目录导入模块在PySpark与Zeppelin中触发ImportError的原因
为什么调用function1时会出现ImportError: No module named file2?
这个问题本质是PySpark分布式执行环境下的模块路径与序列化问题,和你提到的"Pyspark --py-files doesn't work"属于同一类场景,我来拆解原因和解决办法:
错误根源
你在Zeppelin notebook里给Driver节点的sys.path添加了项目路径,所以Driver能找到file1和file2,但PySpark的Worker节点完全是独立的执行环境:
- Driver会把
function1序列化后发送到Worker节点执行,但Worker的sys.path里并没有/home/projects/project1这个目录; - 当Worker反序列化
function1并执行时,会尝试加载它依赖的file2,但此时Worker找不到这个模块,就抛出了ImportError。
另外,file1里用的from file2 import function2属于相对导入,在分布式环境下,这种导入方式依赖于当前脚本的路径上下文,而Worker节点的执行上下文和Driver完全不同,所以无法识别这个相对路径对应的模块。
解决办法
针对这个场景,有几种可靠的解决方式:
1. 用--py-files分发整个项目模块
这是PySpark处理依赖模块的标准方案:
- 把
/home/projects/project1目录打包成zip文件(确保zip里包含__init__.py、file1.py、file2.py以及data文件夹); - 在Zeppelin的Spark interpreter配置里,添加
spark.submit.pyFiles参数,值为/home/projects/project1.zip; - 或者在代码里动态添加:
这样Worker节点会自动下载这个zip包,并添加到自身的Python路径中,就能找到from os import path import sys from pyspark import SparkContext sc = SparkContext.getOrCreate() sc.addPyFile(path.abspath('/home/projects/project1.zip')) from file1 import function1 res = function1(some_input)file2了。
2. 修改模块内的导入为绝对路径
调整file1.py里的导入语句,使用基于项目顶层的绝对导入:
from project1.file2 import function2
同时确保在Driver里把项目父目录加到sys.path(比如sys.path.append('/home/projects')),这样不管是Driver还是Worker,只要路径配置正确,都能通过project1.file2找到对应的模块。
3. 全局设置Worker的Python路径
在Zeppelin的Spark interpreter设置中,添加环境变量PYTHONPATH=/home/projects/project1,这样所有Worker节点启动时都会自动把这个路径加入到Python的搜索路径里,就能识别到file1和file2了。
内容的提问来源于stack exchange,提问作者Mpizos Dimitris
相关产品推荐
相关产品推荐

