AWS EMR PySpark跨Notebook导入函数无法常驻内存问题咨询
AWS EMR PySpark Notebook 跨Notebook函数复用方案
问题复现
- 场景:需要将通用自定义函数统一存放在独立Notebook文件中,供测试、数据加工等多个业务Notebook调用,避免重复编码
- 异常1:使用
%run运行存函数的目标Notebook时,仅当前单元格可正常调用函数,切换到其他单元格触发NameError: name 'f' is not defined - 异常2:通过
sc.install_pypi_package("ipynb")安装ipynb包后,尝试用ipynb.fs.full方式导入目标Notebook,持续触发ModuleNotFoundError: No module named 'ipynb.fs.full.called'
复现代码如下:
被调用的公共Notebook called.ipynb:
# called.ipynb 存放公共逻辑的Notebook print('Hello World') f = lambda x: x**2
调用方caller.ipynb的%run方式复现:
# caller.ipynb 业务调用Notebook ## 单元格1 %run called.ipynb f(4) ## 执行输出: # 'hello world' # 16 ## 单元格2 f(4) ## 执行报错: # NameError: name 'f' is not defined # Traceback (most recent call last): # NameError: name 'f' is not defined
ipynb包导入方式复现:
# 安装ipynb的命令 sc.install_pypi_package("ipynb")
# 单独单元格执行导入 import ipynb from ipynb import fs.full from ipynb.fs.full.called import * # 报错:ModuleNotFoundError: No module named 'ipynb.fs.full.called' # 尝试带.ipynb后缀导入仍失败 from ipynb.fs.full.called.ipynb import * # 报错:ModuleNotFoundError: No module named 'ipynb.fs.full.called'
问题根因
- EMR PySpark Notebook默认的
%run魔法命令执行作用域仅限当前单元格,执行过程中生成的函数、变量不会注入Notebook全局交互内核的命名空间,跨单元格执行时无法找到对应定义 sc.install_pypi_package是PySpark面向集群executor节点的装包接口,安装的依赖不会同步到运行Notebook内核的driver节点,因此内核无法识别安装的ipynb包;同时ipynb包的导入逻辑要求被导入文件所在路径在Python模块搜索路径sys.path中,EMR Notebook默认工作目录不在该路径列表内,双重问题导致模块找不到的报错。
可行解决方案
方案1:公共逻辑存为.py脚本(生产环境优先推荐)
该方案完全避开Notebook格式导入的各类兼容问题,稳定性最高:
- 在Notebook工作目录下新建
common_funcs.py脚本,将所有公共函数、常量、通用逻辑迁移到该文件中,例如:
# common_funcs.py 公共逻辑脚本 print('Hello World') f = lambda x: x**2
- 在所有需要调用公共逻辑的Notebook开头,先将当前工作目录加入Python模块搜索路径,再直接导入即可,导入后的对象在整个Notebook的所有单元格都可正常调用:
import sys import os # 将当前工作目录加入模块搜索路径 sys.path.append(os.getcwd()) # 导入所有公共逻辑 from common_funcs import * # 任意单元格均可直接调用 f(4) # 正常返回16
如果公共脚本有更新,无需重启内核,执行以下代码即可重载最新逻辑:
import importlib import common_funcs importlib.reload(common_funcs) from common_funcs import *
方案2:修复%run命令作用域(适合保留Notebook格式的场景)
如果需要用Notebook格式存放公共逻辑,给%run加-i参数即可,该参数会强制被运行的Notebook在全局交互内核命名空间执行,执行后定义的对象会全局常驻:
# 单元格执行时加-i参数 %run -i called.ipynb f(4) # 返回16
执行完成后,后续任意单元格都可以直接调用called.ipynb中定义的所有函数、变量,不会再触发NameError。
注意:如果公共Notebook和当前Notebook不在同一路径,需要写全文件的相对路径。
方案3:修复ipynb包导入逻辑
如果坚持使用ipynb包的Notebook导入方式,按以下步骤调整即可:
- 不要用
sc.install_pypi_package安装ipynb,该命令不会给driver端的Notebook内核装包,直接用pip在Notebook单元格中给内核装依赖:
!pip install ipynb
- 将当前工作目录加入Python模块搜索路径,再执行导入:
import sys import os sys.path.append(os.getcwd()) from ipynb.fs.full.called import * f(4) # 正常返回16
内容的提问来源于stack exchange,提问作者Francis Smart
相关产品推荐
相关产品推荐

