背景
我在工作中遇到了一个非常相似的问题。我有一个审计文件夹,其中每个文件都有相同的列名,但 Date 列是 StringType 而不是 TimestampType。
作为背景,我最初是一名 C# 开发人员,我已经开始使用 Azure Synapse Analytics。我对使用 Pyspark 还很陌生,所以我花了几天时间解决这个问题,环顾四周,但我一直在努力寻找任何东西。我最终自己想出了一个解决方案,所以我想我会回来为你提供指导或任何处于困境中的未来开发人员。
解决方案
首先,我定义了与我的新文件和正确文件的列匹配的架构。
schema = StructType([,
StructField("Date", TimestampType(), False),
StructField("PipelineName", StringType(), False),
StructField("SourceFileName", StringType(), False),
StructField("ActivityName", StringType(), True),
StructField("InsertedRows", LongType(), True),
StructField("FailedRows", LongType(), True),
StructField("Message", StringType(), True)])
然后,我使用刚刚创建的架构创建了一个空白数据框。
df = spark.createDataFrame(spark.sparkContext.emptyRDD(), schema)
然后我遍历了我的审计目录中的每个文件。
auditDir = "DirectoryNameHere"
for f in mssparkutils.fs.ls(auditDir)
在我的 for 循环中,我使用目录名和文件名来创建文件路径。
我创建了一个新的数据框,它使用查看 Date 列的 withColumn 读取此文件的路径,并将其转换为时间戳。无论该列是 StringType 还是 TimestampType,这似乎都有效。
我认为可以做类似的事情来将你的字符串转换为双精度。
因为我所有的 parquet 文件都有相同的列,所以我只使用了 union 方法而不是 unionByName,这会将这个文件的数据连接到一个不断增长的数据帧中。
path = os.path.join(auditDir, f.name)
newDf = spark.read.parquet(path).withColumn("Date", to_timestamp(col("Date")))
df = df.union(newDf)
出于我的目的,然后我将按照最早日期的顺序将它们写成一个分区。然后将这个新分区写入同一个文件夹。但是,如果您可以写入另一个文件夹并保留旧文件作为备份,我会建议您。
df.orderBy(col("Date")).coalesce(1).write.mode("append").parquet(auditDir)
虽然迭代文件并不理想,但这是我找到的唯一方法。谢天谢地,我的数据量很小,所以没花太长时间。
感谢阅读,希望对你和其他人有很大帮助
-乔什