PySpark通过URL加载CSV时报java.lang.UnsupportedOperationException如何解决
问题原因
该报错的核心是PySpark底层依赖的Hadoop Http/Https文件系统未实现目录列表查询能力:Spark读取文件前默认会先扫描目标路径下的所有文件,该扫描动作需要调用listStatus接口,而Hadoop的HTTP文件系统的listStatus方法直接抛出UnsupportedOperationException异常,因此直接传入HTTP/HTTPS URL会触发报错。
本地文件可正常读取是因为本地文件系统的listStatus接口有完整实现;pandas可正常读取是因为pandas直接调用Python内置的HTTP客户端拉取文件内容,不需要走Hadoop文件系统接口。
可行解决方案
方案1:代码自动下载文件到本地再读取(最适配PyCharm调试场景)
不需要手动拷贝文件,在代码中增加自动下载缓存逻辑即可,既满足URL读取需求,也能避免重复下载浪费带宽:
import os import requests from pyspark.sql import SparkSession def load_csv_from_url(spark, url, cache_path="./temp_csv_cache"): # 创建本地缓存目录 os.makedirs(cache_path, exist_ok=True) # 提取URL对应文件名 file_name = url.split("/")[-1] local_file_path = os.path.join(cache_path, file_name) # 本地无缓存时才发起下载 if not os.path.exists(local_file_path): resp = requests.get(url, timeout=30) resp.raise_for_status() with open(local_file_path, "wb") as f: f.write(resp.content) # 读取本地文件返回Spark DataFrame return spark.read.format("csv").option("header", "true").load(local_file_path) # 调用示例 spark = SparkSession.builder.getOrCreate() url = "https://github.com/BigDaMa/COCOA/raw/master/dataset/movie.csv" df = load_csv_from_url(spark, url) df.show()
该方案无需修改Spark配置,也不需要使用spark-submit启动,完全适配PyCharm调试流程。
方案2:pandas中转(适合小文件场景)
你已确认pandas可正常读取URL对应的CSV文件,直接将pandas DataFrame转为Spark DataFrame即可,代码更简洁:
import pandas as pd from pyspark.sql import SparkSession spark = SparkSession.builder.getOrCreate() url = "https://github.com/BigDaMa/COCOA/raw/master/dataset/movie.csv" pandas_df = pd.read_csv(url) spark_df = spark.createDataFrame(pandas_df) spark_df.show()
注意该方案仅适合文件体积小于Driver节点可用内存的场景,大文件使用该方案会触发Driver节点OOM。
方案3:配置Spark启用HTTP数据源(适合大文件集群场景)
如果文件体积过大不适合走Driver中转,可以在创建SparkSession时添加对应配置,直接支持HTTP URL读取,不需要通过终端spark-submit启动:
from pyspark.sql import SparkSession spark = SparkSession.builder\ .config("spark.sql.files.ignoreMissingFiles", "true")\ .config("spark.hadoop.fs.http.impl", "org.apache.hadoop.fs.http.HttpFileSystem")\ .config("spark.hadoop.fs.https.impl", "org.apache.hadoop.fs.http.HttpsFileSystem")\ .getOrCreate() # 读取时添加wholetext参数避免目录扫描 df = spark.read.format("csv").option("header", "true").option("wholetext", "true").load(url) df.show()
该方案要求Spark版本≥3.0,部分低版本Hadoop环境可能存在兼容性问题,优先选择前两种方案。
内容的提问来源于stack exchange,提问作者Meike
相关产品推荐
相关产品推荐

