spark.read.json()如何通过动态年份参数读取指定范围S3文件
实现方案
你现在的目录是标准的年/月/日/小时分层分区结构,完全不需要移动现有文件,下面两种方案都能实现只读2020年及以后数据的需求,根据场景选就可以:
方案1:通配符枚举目标年份(性能最好)
直接在年份对应的路径层用大括号枚举需要的年份,S3A客户端会直接跳过2018、2019的顶层目录,根本不会去扫这两个年份下的文件,列目录的开销最低,适合临时提数、年份范围固定的场景。
代码如下:
df = spark.read.json("s3a://my-data/data-events/{2020,2021,2022}/*/*/*/*.json")
后续如果新增2023、2024的目录,只要在大括号里追加对应年份值就行。
方案2:分区发现+自动裁剪(免代码维护)
如果是长期跑的线上定时任务,不想每年手动改代码加年份,可以用Spark自带的分区裁剪能力:
- 读取时通过
basePath参数指定分区根目录,Spark会自动把路径里的year/month/day/hour解析成DataFrame的分区列 - 直接对
year列加>= 2020的过滤条件,Spark优化器会自动跳过不符合条件的分区目录,不会读2020年之前的文件
代码如下:
df = spark.read \ .option("basePath", "s3a://my-data/data-events/") \ .json("s3a://my-data/data-events/*/*/*/*/*.json") target_df = df.filter("year >= 2020")
Spark 2.4及以上版本默认就开了分区裁剪(对应参数spark.sql.optimizer.partitionPruning默认值为true),不需要额外改配置。后续新增年份目录的时候,不用改代码就能自动读取符合year >=2020条件的数据。
踩坑提醒
- 不要直接读完全量数据再做过滤:如果不指定
basePath,Spark不会把路径里的年份解析成独立列,这时候加过滤条件会先把所有年份的文件全读进来再筛数据,性能会差很多。 - 你原来用的通配符
*/*/*/*/*会把目录下的非json文件(比如Spark写的_SUCCESS标记、.crc校验文件)也扫进来,建议最后一层用*.json做后缀匹配,避免读入无效文件。
内容的提问来源于stack exchange,提问作者Jacky
相关产品推荐
相关产品推荐

