PySpark RDD.pipe调用外部进程触发FileNotFoundError问题求助
问题场景
尝试通过PySpark的RDD.pipe调用外部dotnet进程失败,使用以下测试代码验证:
spark = SparkSession.builder.master("local").appName("test").getOrCreate() result_rdd = spark.sparkContext.parallelize(['1', '2', '', '3']).pipe(command).collect()
执行后抛出错误,核心报错为:
FileNotFoundError: [WinError 2] The system cannot find the file specified
完整错误栈:
py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe.
: org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 0.0 failed 1 times, most recent failure: Lost task 0.0 in stage 0.0 (TID 0) ( executor driver): org.apache.spark.api.python.PythonException: Traceback (most recent call last):
File "C:\projectpath.venv\Lib\site-packages\pyspark\python\lib\pyspark.zip\pyspark\worker.py", line 686, in main
File "C:\projectpath.venv\Lib\site-packages\pyspark\python\lib\pyspark.zip\pyspark\worker.py", line 676, in process
File "C:\projectpath.venv\lib\site-packages\pyspark\rdd.py", line 540, in func
return f(iterator)
File "C:\projectpath.venv\lib\site-packages\pyspark\rdd.py", line 1117, in func
pipe = Popen(shlex.split(command), env=env, stdin=PIPE, stdout=PIPE)
File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 951, in init
self._execute_child(args, executable, preexec_fn, close_fds,
File "C:\Users\username\AppData\Local\Programs\Python\Python39\lib\subprocess.py", line 1420, in _execute_child
hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
FileNotFoundError: [WinError 2] The system cannot find the file specified
错误原因
Spark Worker进程无法定位pipe方法传入的command对应的可执行文件,常见诱因:
- 未指定dotnet程序/命令的完整绝对路径
- 目标程序不在系统PATH环境变量中
- Windows环境下命令格式解析异常
解决方法
1. 使用完整绝对路径
直接在command中指定dotnet可执行文件或你的应用的完整路径:
# 调用dotnet独立exe command = r"C:\your-app-path\my-dotnet-app.exe" # 调用dotnet运行dll command = r'"C:\Program Files\dotnet\dotnet.exe" "C:\your-app-path\my-dotnet-app.dll"'
2. 将程序加入系统PATH
把dotnet命令或你的应用所在目录添加到系统PATH环境变量,重启Python/Spark环境后,可直接使用程序名:
command = "my-dotnet-app.exe" # 或 command = "dotnet my-dotnet-app.dll"
3. 用列表形式传入命令(Windows推荐)
避免shlex.split在Windows下的解析问题,直接传入参数列表:
command = [r"C:\Program Files\dotnet\dotnet.exe", r"C:\your-app-path\my-dotnet-app.dll"] result_rdd = spark.sparkContext.parallelize(['1', '2', '', '3']).pipe(command).collect()
4. 本地终端预验证命令
先在cmd/PowerShell中执行目标dotnet命令,确认能正常运行,排除程序自身或路径问题。
内容的提问来源于stack exchange,提问作者peterlustig

