Python 从pyspark中的json文件中使用模式读取固定宽度的文件
我有固定宽度的文件如下Python 从pyspark中的json文件中使用模式读取固定宽度的文件,python,apache-spark,pyspark,pyspark-sql,Python,Apache Spark,Pyspark,Pyspark Sql,我有固定宽度的文件如下 00120181120xyz12341 002220180203ABC56792 00320181203pqr25483 以及相应的JSON文件,用于指定模式: {“列”:“id”,“从”:“1”,“到”:“3”} {“列”:“日期”,“从”:“4”,“到”:“8”} {“Column”:“name”,“From”:“12”,“To”:“3”} {“列”:“工资”,“从”:“15”,“到”:“5”} 我使用以下命令将架构文件读入数据帧: SchemaFile = sp
00120181120xyz12341
002220180203ABC56792
00320181203pqr25483
以及相应的JSON
文件,用于指定模式:
{“列”:“id”,“从”:“1”,“到”:“3”}
{“列”:“日期”,“从”:“4”,“到”:“8”}
{“Column”:“name”,“From”:“12”,“To”:“3”}
{“列”:“工资”,“从”:“15”,“到”:“5”}
我使用以下命令将架构文件读入数据帧:
SchemaFile = spark.read\
.format("json")\
.option("header","true")\
.json('C:\Temp\schemaFile\schema.json')
SchemaFile.show()
#+------+----+---+
#|Column|From| To|
#+------+----+---+
#| id| 1| 3|
#| date| 4| 8|
#| name| 12| 3|
#|salary| 15| 5|
#+------+----+---+
同样,我正在将固定宽度文件解析为pyspark数据帧,如下所示:
File = spark.read\
.format("csv")\
.option("header","false")\
.load("C:\Temp\samplefile.txt")
File.show()
#+-------------------+
#| _c0|
#+-------------------+
#|00120181120xyz12341|
#|00220180203abc56792|
#|00320181203pqr25483|
#+-------------------+
显然,我可以对每列的位置和长度值进行硬编码,以获得所需的输出:
from pyspark.sql.functions import substring
data = File.select(
substring(File._c0,1,3).alias('id'),
substring(File._c0,4,8).alias('date'),
substring(File._c0,12,3).alias('name'),
substring(File._c0,15,5).alias('salary')
)
data.show()
#+---+--------+----+------+
#| id| date|name|salary|
#+---+--------+----+------+
#|001|20181120| xyz| 12341|
#|002|20180203| abc| 56792|
#|003|20181203| pqr| 25483|
#+---+--------+----+------+
但是如何使用
SchemaFile
DataFrame来指定行的宽度和列名,以便动态应用模式(无需硬编码)在运行时?这里最简单的方法是收集SchemaFile
的内容,并在其行上循环以提取所需的数据
首先将模式文件作为JSON读取到数据帧中。然后调用collect并将每行映射到字典:
sfDict = map(lambda x: x.asDict(), SchemaFile.collect())
print(sfDict)
#[{'Column': u'id', 'From': u'1', 'To': u'3'},
# {'Column': u'date', 'From': u'4', 'To': u'8'},
# {'Column': u'name', 'From': u'12', 'To': u'3'},
# {'Column': u'salary', 'From': u'15', 'To': u'5'}]
现在,您可以在sfDict
中的行上循环,并使用这些值对列进行子串:
from pyspark.sql.functions import substring
File.select(
*[
substring(
str='_c0',
pos=int(row['From']),
len=int(row['To'])
).alias(row['Column'])
for row in sfDict
]
).show()
#+---+--------+----+------+
#| id| date|name|salary|
#+---+--------+----+------+
#|001|20181120| xyz| 12341|
#|002|20180203| abc| 56792|
#|003|20181203| pqr| 25483|
#+---+--------+----+------+
请注意,我们必须将转换为
并将从
转换为整数,因为它们在json
文件中被指定为字符串。您担心什么?您尝试了什么?我想在作为运行时读取数据时对数据应用模式。不是硬编码的