Apache Toree 0.5.0-incubating 常用命令与 magic 详解

系统讲解 Apache Toree 0.5.0-incubating 的 jupyter toree install 全部参数、kernel.json 与 run.sh 启动链路、内核管理与 nbconvert 调试命令,以及 %AddJar/%AddDeps/%ShowTypes/%%SQL/%%HTML 等 magic 的逐个实测行为与异常结论,全部已在 Ubuntu 22.04 实测。

Apache ToreeApache Toree2026/10/15

Apache Toree 0.5.0-incubating 常用命令与 magic 详解

目标:系统掌握 Apache Toree 0.5.0-incubating 的命令面与 magic 面——jupyter toree install 全参数、kernel.json 与 run.sh 的启动链路、kernelspec 管理与 nbconvert 调试命令,以及 %AddJar、%AddDeps、%ShowTypes、%%SQL、%%HTML 等 magic 的逐个实测行为(含 %Truncate 不存在、%ShowOutput 不生效两项实测异常结论)。以下全部命令与回显均已在 Ubuntu 22.04(x86_64)、OpenJDK 1.8.0_504、Spark 3.0.3 实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • JDK:OpenJDK 1.8.0_504(Toree 0.5.0 + Spark 3.0.3 的实测可用组合)
  • Python:3.10.12,Jupyter notebook 7.6.3、jupyter_core 5.9.1
  • 内核:apache-toree 0.5.0(pip 包,内核 jar toree-assembly-0.5.0-incubating.jar)
  • Spark:spark-3.0.3-bin-hadoop2.7(/usr/local/spark)
  • 内核目录:/usr/local/share/jupyter/kernels/(系统级注册)
  • 验证用工作目录:/root/toree-test

确认已注册内核(实时回显):

jupyter kernelspec list
Available kernels:
  apache_toree_scala    /usr/local/share/jupyter/kernels/apache_toree_scala
  python3               /usr/local/share/jupyter/kernels/python3

二、安装与注册命令:jupyter toree install 全参数

jupyter toree install 是 Toree 唯一的注册入口,本质是把 pip 包内的 toree 目录复制为 kernelspec 并生成 kernel.json。全部参数如下(前六项为 Toree 专有,后四项为 Jupyter 通用;依据官方 Installation 文档与实测):

参数默认值作用实测要点
--spark_home/usr/local/spark(或环境变量 SPARK_HOME)写入 kernel.json 的 env.SPARK_HOME必须指向解压后的 Spark 目录(含 bin/spark-submit)
--kernel_nameApache Toree内核注册名前缀与显示名生成 toree_local2_scala 形式的目录名(空格转下划线、转小写)
--interpretersScala要注册的解释器列表,逗号分隔合法值只有 Scala、SQL(区分大小写)
--spark_opts空写入 env.__TOREE_SPARK_OPTS__如 --master=local[2],运行时会被同名外部变量覆盖
--toree_opts空写入 env.__TOREE_OPTS__如 --spark-context-initialization-mode none
--python_execpythonSQL 解释器回调 Python 时的可执行文件el8/py3 场景建议显式 python3
--replace关覆盖同名已注册内核改配置重注册时必加,否则报已存在
--user关注册到 ~/.local/share/jupyter/kernels无 root 权限时用
--sys-prefix关注册到 sys.prefix 下conda/虚拟环境专用
--debug关日志级别 DEBUG排查注册问题时加

四个实测锚点:

--kernel_name 决定目录名(实测注册名为 Toree Local2 时目录名是小写下划线形式):

jupyter toree install --spark_home=/usr/local/spark --kernel_name='Toree Local2' --spark_opts='--master=local[2]' --replace
[ToreeInstall] Creating kernel Scala
[ToreeInstall] Installed kernelspec toree_local2_scala in /usr/local/share/jupyter/kernels/toree_local2_scala

--interpreters=Scala,SQL 一次注册两个内核:

jupyter toree install --spark_home=/usr/local/spark --kernel_name='Toree Dual' --interpreters=Scala,SQL --replace
jupyter kernelspec list | grep toree_dual
[ToreeInstall] Creating kernel Scala
[ToreeInstall] Installed kernelspec toree_dual_scala in /usr/local/share/jupyter/kernels/toree_dual_scala
[ToreeInstall] Creating kernel SQL
[ToreeInstall] Installed kernelspec toree_dual_sql in /usr/local/share/jupyter/kernels/toree_dual_sql
  toree_dual_scala      /usr/local/share/jupyter/kernels/toree_dual_scala
  toree_dual_sql        /usr/local/share/jupyter/kernels/toree_dual_sql

--interpreters 传非法值时跳过并告警(实测传 PySpark):

[ToreeInstall] Creating kernel PySpark
[ToreeInstall] ERROR] Unknown interpreter PySpark. Skipping installation of PySpark interpreter

⚠️ 注意:--toree_opts 与 --spark_opts 中的引号会原样写入 kernel.json 的 env,含空格的参数值用单引号包裹整个 opts 值;运行时如需临时改参,设置外部环境变量 TOREE_OPTS/SPARK_OPTS 优先级高于 kernel.json 内的占位值(run.sh 逻辑见第三章)。

三、内核启动机制解析

理解 kernel.json → run.sh → spark-submit 的三层链路,是定位「内核起不来」的基础。

第一层,kernel.json(Jupyter 读取的入口):

cat /usr/local/share/jupyter/kernels/apache_toree_scala/kernel.json
{
  "argv": [
    "/usr/local/share/jupyter/kernels/apache_toree_scala/bin/run.sh",
    "--profile",
    "{connection_file}"
  ],
  "env": {
    "DEFAULT_INTERPRETER": "Scala",
    "__TOREE_SPARK_OPTS__": "",
    "__TOREE_OPTS__": "",
    "SPARK_HOME": "/usr/local/spark"
  },
  "display_name": "Apache Toree - Scala",
  "language": "scala",
  "interrupt_mode": "signal",
  "metadata": {},
  "kernel_protocol_version": ""
}

第二层,run.sh 的关键逻辑(节选自 /usr/local/share/jupyter/kernels/apache_toree_scala/bin/run.sh,与文件逐行一致):

PROG_HOME="$(cd "`dirname "$0"`"/..; pwd)"

if [ -z "$SPARK_HOME" ]; then
  echo "SPARK_HOME must be set to the location of a Spark distribution!"
  exit 1
fi

echo "Starting Spark Kernel with SPARK_HOME=$SPARK_HOME"

KERNEL_ASSEMBLY=`(cd ${PROG_HOME}/lib; ls -1 toree-assembly-*.jar;)`

# disable randomized hash for string in Python 3.3+
export PYTHONHASHSEED=0
TOREE_ASSEMBLY=${PROG_HOME}/lib/${KERNEL_ASSEMBLY}
# The SPARK_OPTS values during installation are stored in __TOREE_SPARK_OPTS__. This allows values to be specified during
# install, but also during runtime. The runtime options take precedence over the install options.
if [ "${SPARK_OPTS}" = "" ]
then
   SPARK_OPTS=${__TOREE_SPARK_OPTS__}
fi

if [ "${TOREE_OPTS}" = "" ]
then
   TOREE_OPTS=${__TOREE_OPTS__}
fi

eval exec \
     "${SPARK_HOME}/bin/spark-submit" \
     --name "'Apache Toree'" \
     "${SPARK_OPTS}" \
     --class org.apache.toree.Main \
     "${TOREE_ASSEMBLY}" \
     "${TOREE_OPTS}" \
     "$@"

第三层,最终执行的等价命令(手动复现用,也是最快的报错定位法):

/usr/local/spark/bin/spark-submit \
  --name 'Apache Toree' \
  --class org.apache.toree.Main \
  /usr/local/share/jupyter/kernels/apache_toree_scala/lib/toree-assembly-0.5.0-incubating.jar \
  --profile {connection_file}

逐项说明:

  • SPARK_HOME 缺失时 run.sh 直接退出并打印提示,这是「内核秒死」的最常见原因之一。
  • SPARK_OPTS/TOREE_OPTS 的优先级:外部环境变量 > kernel.json 内的 __TOREE_SPARK_OPTS__/__TOREE_OPTS__ 占位值(脚本里先取空判断再回退)。
  • 内核以 spark-submit --class org.apache.toree.Main 方式运行,因此内核进程的 JVM 版本由 Spark 的启动脚本决定——这就是 JDK 版本配对必须匹配 Spark 的根因。
  • --profile {connection_file} 是 Jupyter 传入的连接文件(运行时替换为实际路径),内核据此建立 5 个 ZeroMQ 通道;手动复现时不传该参数内核会在启动后等待连接,用于只看启动报错时加 --spark-context-initialization-mode none 并限时执行。

四、内核管理命令

注册/列出/删除/覆盖四个高频操作(实时回显):

jupyter toree install --spark_home=/usr/local/spark --replace
[ToreeInstall] Creating kernel Scala
[ToreeInstall] Installed kernelspec apache_toree_scala in /usr/local/share/jupyter/kernels/apache_toree_scala
jupyter kernelspec list
Available kernels:
  apache_toree_scala    /usr/local/share/jupyter/kernels/apache_toree_scala
  python3               /usr/local/share/jupyter/kernels/python3
jupyter kernelspec remove toree_local2_scala -y
Kernel specs to remove:
  toree_local2_scala    /usr/local/share/jupyter/kernels/toree_local2_scala
Removed 1 kernelspecs

查看指定内核详情:

jupyter kernelspec list --json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['kernelspecs']['apache_toree_scala']['spec']['display_name'])"
Apache Toree - Scala

逐项说明:

  • --replace:不加时重复注册同名内核会报已存在错误;改 --spark_home/--spark_opts/--toree_opts 后必须带 --replace 重注册。
  • jupyter kernelspec remove 内核名 -y:直接删除 kernelspec 目录(如上文实测的 toree_local2_scala),pip 卸载 apache-toree 不会连带删除已注册内核。
  • 权限隔离:--user 注册到 ~/.local/share/jupyter/kernels/,--sys-prefix 注册到 sys.prefix;jupyter kernelspec list 会按搜索路径全部列出,同名时用户级覆盖系统级。

五、执行与调试命令

5.1 nbconvert 批量执行(本文实测的主路径)

cd /root/toree-test && timeout 300 jupyter nbconvert --to notebook --execute \
  --ExecutePreprocessor.timeout=240 first.ipynb --output first-out.ipynb
[NbConvertApp] Writing 1302 bytes to first-out.ipynb

三个关键开关:

  • --ExecutePreprocessor.timeout=240:单单元格超时(秒)。Toree 内核冷启动含 Spark 初始化约 40~60 秒,给足超时。
  • --allow-errors:单元格出错时不中断整个 notebook,错误保留在输出里继续执行(本文各实测 notebook 均开启,便于收集全部行为)。
  • --output:指定输出文件名(如上文的 first-out.ipynb);不加 --output 会覆盖原文件。

5.2 jupyter console 交互执行

printf 'val a = 3\na * 7\nexit\n' | timeout 240 jupyter console --kernel apache_toree_scala
Jupyter console 6.6.3
Apache ToreeIn [1]:

In [1]: val a = 3
...
Do you really want to exit ([y]/n)?
Shutting down kernel

实测要点:console 能启动内核并逐行求值(回显里可见内核加载的 (Scala,...) 与 (SQL,...) 解释器清单),但非终端管道模式下结果渲染受限(实测 Out[2] 行的值未正常回显,日志出现 WARN KernelOutputStream: Suppressing empty output: '');交互验证请优先用 JupyterLab/notebook 界面或 nbconvert。

5.3 手动 spark-submit 定位法

内核秒死时,绕开 Jupyter 直接复现启动报错(实测 JDK 17 下的输出):

timeout 60 /usr/local/spark/bin/spark-submit --class org.apache.toree.Main \
  /usr/local/share/jupyter/kernels/apache_toree_scala/lib/toree-assembly-0.5.0-incubating.jar \
  --spark-context-initialization-mode none 2>&1 | grep -m2 -E 'Exception|Caused'
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make private java.nio.DirectByteBuffer(long,int) accessible: module java.base does not "opens java.nio" to unnamed module @4f51ab48

验证点:Jupyter 侧只报 Kernel died before replying to kernel_info,而此法直接给出根因(JDK 17 不被 Spark 3.0 支持)。版本配对结论与两种失败模式详见第 1 篇第三章。

六、magic 详解

Toree 的 magic 分行 magic(%Name,作用于声明)与单元格 magic(%%Name,作用于整格)。以下全部为 0.5.0 内核实测行为,按「实测可用 / 实测异常 / 未覆盖」三档归类。

6.1 实测可用 magic

%AddJar:行 magic,向运行时 classpath 添加 jar,支持远程 URL 与 file:// 本地路径。实测(Maven Central 直链):

[stream] Starting download from https://repo1.maven.org/maven2/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar
[stream] Finished download of commons-math3-3.6.1.jar

同一 URL 第二次执行输出 Using cached version of commons-math3-3.6.1.jar(内置缓存)。import 必须写在 AddJar 之后的单元格。

%AddDeps:行 magic,按 Maven/Ivy 坐标解析并加载依赖。实测 org.apache.commons:commons-math3:3.6.1:

[stream] Marking org.apache.commons:commons-math3:3.6.1 for download
[stream] Obtained 2 files

随后单元格 import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics 并计算,实测输出 mean=4.0(数据 {2.0,4.0,6.0})。要点:坐标按 groupId artifactId version 空格分隔;实测输出流中 Marking.../Obtained... 各出现两次,属 0.5.0 的重复日志行为,不影响加载结果。

%ShowTypes:行 magic,开关式(on/off),开启后求值结果带类型标注。实测元组:

[stream] Types will be printed.
[display_data] {'text/plain': 't: (Int, String) = (1,a)'}
[execute_result] {'text/plain': '(Int, String) = (1,a)'}

%%SQL:单元格 magic,整格按 SQL 解释执行,execute_result 直接返回结果表(实测 Spark 3.0.3):

[execute_result] {'text/plain': '+---+-----+\n|two| name|\n+---+-----+\n|  2|toree|\n+---+-----+'}

%%HTML:单元格 magic,整格按 HTML 输出(实测返回 text/html MIME):

[execute_result] {'text/html': '<h1>Toree HTML Magic</h1>'}

6.2 实测异常 magic(0.5.0 如实披露)

%Truncate 不存在。实测 %Truncate on 直接报错(尽管 0.3.0 的 RELEASE_NOTES 提及过 %Truncate 修复):

[error] Error parsing magics! : Magics [Truncate] do not exist!

%ShowOutput off 不生效。实测 %ShowOutput off 后,虽回显确认声明 Console output will NOT be shown.,但同单元格内 println 的输出仍然照常出现在 stream 中:

[stream] Console output will NOT be shown.
Console output will NOT be shown.
this line should be hidden

结论:0.5.0 上不要依赖 %Truncate 与 %ShowOutput 控制输出,长结果截断在 notebook 前端自行处理,隐藏输出用单元格注释或不调用 println。

未知 magic 的报错形态:任何未注册的 magic 统一返回 error 输出 Error parsing magics! : Magics [<名字>] do not exist!,内核不崩溃、后续单元格正常执行(实测 %FooBar)。

6.3 未覆盖项

官方文档体系还提及 %AddRsrc、%JavaScript 等资源/脚本类 magic,本文未实测,行为以官方 Magics 文档为准;--interpreters=SQL 注册的 SQL 专属内核在实测中执行挂起(InterpreterActor 的 AskTimeoutException),建议生产统一使用 Scala 内核 + %%SQL 组合(详见第 5 篇)。

💡 技术拓展:Jupyter 内核生态里 magic 能力的三档实现对比——

内核magic 体系代表能力
IPython(Python)最丰富%%timeit、%%bash、%%capture 等数十个
Apache Toree(Scala/SQL)精简依赖加载(%AddJar/%AddDeps)、输出控制(%ShowTypes)、SQL/HTML 单元格
sparkmagic(经 Livy)面向远程%%spark 会话管理、SQL 取数转 pandas

本文实测采用 Apache Toree:其 magic 覆盖了「带依赖跑 Spark + SQL 探索」的最小闭环,与 IPython 生态互补。

七、常见问题(FAQ)

Q1:jupyter toree install 报 Unknown interpreter PySpark. Skipping installation? 合法值只有 Scala 与 SQL(区分大小写)。PySpark/R 内置解释器自 0.3.0 移除(官方 RELEASE_NOTES 明示),需要 PySpark 时另用 pyspark 内核方案。

Q2:改了 --spark_opts 重注册但没生效? 检查三点:重注册是否带 --replace;notebook 元数据里的 kernelspec.name 是否指向新内核名;是否有同名外部环境变量 SPARK_OPTS 覆盖了 kernel.json 的占位值(run.sh 的优先级逻辑见第三章)。

Q3:怎么确认内核实际使用的 Spark 版本与 master? 在单元格执行 println(spark.version + " @ " + sc.master)。实测 --spark_opts='--master=local[2]' 注册的内核输出 master=local[2]、appName=Apache Toree。

Q4:%AddDeps 能否加载带传递依赖的库? 可以,坐标解析含传递依赖(实测 commons-math3 这种零依赖库取回 jar+pom 共 2 个文件)。公司内网可指向自建 Nexus(%AddDeps 支持自定义 resolver,官方 0.3.0 引入);下载地址固定时用 %AddJar 更直接。

Q5:单元格超时被杀但不知道卡在哪? 分两步:nbconvert 侧看 --ExecutePreprocessor.timeout 到期信息;然后手动 spark-submit 复现(5.3 节)确认是内核启动问题还是代码问题。SQL 类单元格挂起优先怀疑 SQL 专属内核(见 6.3 节),换 Scala 内核 + %%SQL 重试。

八、参考链接

  1. 官方 Installation(jupyter toree install 参数原文):https://toree.apache.org/docs/current/user/installation
  2. 官方 Magics Overview:https://toree.apache.org/docs/current/user/magics
  3. 官方 RELEASE_NOTES(各版本 magic 演进):https://github.com/apache/incubator-toree/blob/master/RELEASE_NOTES.md
  4. Apache Toree 安装(本文配套第 1 篇):/docs/Apache Toree/Ubuntu 22.04 安装 Apache Toree 指南.md
  5. 快速入门与集成示例(本文配套第 3 篇):/docs/Apache Toree/Apache Toree 0.5.0-incubating 快速入门与集成示例.md