You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySpark读取Azure Blob中大于2GB的JSON文件失败报错

解决Spark读取大于2GB JSON文件时的BufferHolder溢出问题

问题根源:开启multiline=true后,Spark会把整个JSON文件当作单条记录加载,而JVM整数的上限是2147483647字节(约2GB),当文件超过这个阈值时,缓冲区无法扩容就会触发IllegalArgumentException: Cannot grow BufferHolder, exceeds 2147483632 bytes错误。

以下是几种可行的解决办法:

1. 拆分大JSON文件

把大于2GB的JSON文件拆成多个1GB以内的小文件,保留原有嵌套结构不变。可以用Azure CLI、Python脚本或第三方工具处理Blob存储里的文件,拆分后再用原代码读取即可。

2. 转换为JSON Lines格式并关闭multiline模式

如果JSON结构允许,将文件转为每行一个JSON对象的JSON Lines格式(比如把原文件的features数组拆成每行一个元素),然后移除option('multiline','true')配置,让Spark按行读取,大幅降低内存压力。

3. 调整Spark内存参数(仅作备选)

尝试调大Executor和Driver的内存以及缓冲区参数,但受限于JVM整数上限,该方法仅能解决接近2GB的文件,无法处理超过2GB的单记录加载:

# 提交Spark作业时添加参数
spark-submit \
  --executor-memory 16G \
  --driver-memory 8G \
  --conf spark.sql.buffer.size=10485760 \
  your_script.py

4. 用RDD结合流式JSON解析库处理

如果以上方法都无法实现,可通过RDD API结合ijson这类流式JSON解析库,分块读取并解析大文件,避免一次性加载整个文件到内存:

from pyspark.sql import Row
from azure.storage.blob import BlobClient
import ijson

def parse_large_json(blob_path):
    # 替换为你的Azure Blob连接信息
    conn_str = "your-storage-connection-string"
    container_name = "your-container-name"
    
    blob_client = BlobClient.from_connection_string(conn_str, container_name, blob_path)
    with blob_client.download_blob() as stream:
        parser = ijson.parse(stream)
        doc_type = None
        current_props = {}
        current_geom = {}
        
        for prefix, event, value in parser:
            # 捕获文档类型
            if prefix == "type" and event == "string":
                doc_type = value
            # 开始解析features.item的properties
            elif prefix == "features.item.properties" and event == "start_map":
                current_props = {}
            elif prefix.startswith("features.item.properties.") and event in ["string", "number"]:
                key = prefix.split(".")[-1]
                current_props[key] = value
            # 开始解析features.item的geometry
            elif prefix == "features.item.geometry" and event == "start_map":
                current_geom = {}
            elif prefix.startswith("features.item.geometry."):
                key = prefix.split(".")[-1]
                if event == "start_array":
                    current_geom[key] = []
                elif event == "end_array":
                    continue
                else:
                    if isinstance(current_geom.get(key), list):
                        current_geom[key].append(value)
                    else:
                        current_geom[key] = value
            # 完成一个feature的解析,生成Row
            elif prefix == "features.item" and event == "end_map":
                yield Row(type=doc_type, **current_props, json_geometry=current_geom)
                current_props = {}
                current_geom = {}

# 读取Blob文件并生成DataFrame
rdd = spark.sparkContext.parallelize([fp_in]).flatMap(parse_large_json)
df = spark.createDataFrame(rdd)

注意:需要在所有Spark Executor节点上安装ijson和azure-storage-blob库,并确保Executor有足够内存处理单条feature数据。

内容的提问来源于stack exchange,提问作者epicman25

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 20:37:38