读取 JSON 文件并获取正确的数据类型:InferShema 给我带来了问题,并且将其设置为 false 不是一个选项

问题描述 投票:0回答:1

我正在构建一个数据存储库,并从源应用程序的 API 中获取 JSON 格式的数据。这些 JSON 非常复杂,它们的结构可能会因调用而变化,因为我每天在初始加载后只获取更改的记录。 使用 Lakehouse 架构,目标是为每个实体提供一个镶木地板表,其中附加每天带来的更改记录(增量)。

问题是: 有时,JSON 中的某些字段通常是带小数的数字(假设为此参数支付的金额),其值为 0,并且 Spark.read.json() 推断该字段的数据类型为 LongType。现在,当不同的文件使 Spark 根据这些字段的值(当值为 0 时为 LongType,当值为 0.8 时为 DoubleType)时,spark 会根据这些字段的值推断出同一文件的 DataType 不同,这将使向现有表追加新数据成为一个问题

面对这个问题,下意识的反应是:让我们规范化架构 - 所有推断的字段都被“强制转换”为 double,并且将新数据附加到 parquet 表中不再有问题。

好吧,更有经验的读者可能会嘲笑这种可能的修复,因为它带来了一个非常明显的(事后看来)问题......当然,现有表和数据帧的模式(带有新数据的 JSON当天读为 Spark df)我现在尝试附加到它,但尝试将值 0 放入期待 Double 的字段中也会炸毁所有内容。

有人有可能解决这个问题吗?

json pyspark struct microsoft-fabric
1个回答
0
投票

经过一番搜索(痛苦)却一无所获后,我决定重新思考整个过程并提出了一个解决方案:使用来自 API 的数据创建数据帧,并且已经具有正确的模式 - 如果 JSON 保存在Lakehouse 具有预期(正确)模式(通过保存从响应中创建的 df,并将预期模式“硬编码”作为参数),只需推断它,它将在 ETL 过程中进一步读入具有正确模式的数据帧,因此首先避免了这个问题。

现在,正确的方法是从头开始编写模式,但由于我很懒且容易分心,所以我用“janky”的方式做到了:使用

inferSchema = true
创建数据框,复制文本输出
print(df.schema)
,更改了需要更改的内容,并创建了一个变量
fullSchema
,并对该输出进行了硬编码,并在首先创建 df 时将其作为模式传递:

if response.status_code == 200 and len(response.json()) != 0:
        fileToLoad = spark.read.option("multiline","true").schema(fullSchema).json(sc.parallelize([json.dumps(response.json())]))
© www.soinside.com 2019 - 2024. All rights reserved.