我正在根据RDD创建一个DataFrame,其中一个值为date
。我不知道如何在架构中指定DateType()
。
让我说明当前的问题-
我们可以将date
加载到DataFrame中的一种方法是,首先将其指定为字符串,然后使用to_date()函数将其转换为正确的date
。
from pyspark.sql.types import Row, StructType, StructField, StringType, IntegerType, DateType
from pyspark.sql.functions import col, to_date
values=sc.parallelize([(3,'2012-02-02'),(5,'2018-08-08')])
rdd= values.map(lambda t: Row(A=t[0],date=t[1]))
# Importing date as String in Schema
schema = StructType([StructField('A', IntegerType(), True), StructField('date', StringType(), True)])
df = sqlContext.createDataFrame(rdd, schema)
# Finally converting the string into date using to_date() function.
df = df.withColumn('date',to_date(col('date'), 'yyyy-MM-dd'))
df.show()
+---+----------+
| A| date|
+---+----------+
| 3|2012-02-02|
| 5|2018-08-08|
+---+----------+
df.printSchema()
root
|-- A: integer (nullable = true)
|-- date: date (nullable = true)
有没有一种方法,我们可以在DateType()
中使用schema
,而不必将string
显式转换为date
?
类似的东西-
values=sc.parallelize([(3,'2012-02-02'),(5,'2018-08-08')])
rdd= values.map(lambda t: Row(A=t[0],date=t[1]))
# Somewhere we would need to specify date format 'yyyy-MM-dd' too, don't know where though.
schema = StructType([StructField('A', DateType(), True), StructField('date', DateType(), True)])
更新:根据 @ user10465355 的建议,以下代码有效-
import datetime
schema = StructType([
StructField('A', IntegerType(), True),
StructField('date', DateType(), True)
])
rdd= values.map(lambda t: Row(A=t[0],date=datetime.datetime.strptime(t[1], "%Y-%m-%d")))
df = sqlContext.createDataFrame(rdd, schema)
df.show()
+---+----------+
| A| date|
+---+----------+
| 3|2012-02-02|
| 5|2018-08-08|
+---+----------+
df.printSchema()
root
|-- A: integer (nullable = true)
|-- date: date (nullable = true)
答案 0 :(得分:3)
长话短说,不适用于与外部对象RDD
一起使用的架构-声明的类型应反映数据的实际状态,而不是所需的状态。
换句话说,允许:
schema = StructType([
StructField('A', IntegerType(), True),
StructField('date', DateType(), True)
])
与date
字段should use datetime.date
相对应的数据。例如,以您的RDD[Tuple[int, str]]
:
import datetime
spark.createDataFrame(
# Since values from the question are just two element tuples
# we can use mapValues to transform the "value"
# but in general case you'll need map
values.mapValues(datetime.date.fromisoformat),
schema
)
与预期行为最接近的方法是使用RDD[Row]
用JSON阅读器转换数据(dicts
)
from pyspark.sql import Row
spark.read.schema(schema).json(rdd.map(Row.asDict))
或更好的显式JSON转储:
import json
spark.read.schema(schema).json(rdd.map(Row.asDict).map(json.dumps))
但这当然比显式转换(BTW)要昂贵得多,而BTW在诸如您描述的简单情况下很容易实现自动化:
from pyspark.sql.functions import col
(spark
.createDataFrame(values, ("a", "date"))
.select([col(f.name).cast(f.dataType) for f in schema]))