Pyspark - 将rdd转换为数据框时数据设置为null

Posted

技术标签:

【中文标题】Pyspark - 将rdd转换为数据框时数据设置为null【英文标题】:Pyspark - Data set to null when converting rdd to dataframe 【发布时间】:2017-11-03 16:25:23 【问题描述】:

使用 PySpark,我正在尝试将嵌套字典的 RDD 转换为数据框,但我在某些设置为 null 的字段中丢失了数据。

代码如下:

sc = SparkContext()
sqlContext = SQLContext(sc)

def convert_to_row(d):
    return Row(**d)

df2 = sc.parallelize(["id": "14yy74hwogxoyl2l3v", "geoloc": "country": "geoname_id": 3017382, "iso_code": "FR", "name": "France"]).map(convert_to_row).toDF()
df2.printSchema()
df2.show()
df2.toJSON().saveAsTextFile("/tmp/json.test")

当我查看 /tmp/json.test 时,内容如下(手动缩进后):


    "geoloc": 
        "country": 
            "name": null,
            "iso_code": null,
            "geoname_id": 3017382
        
    ,
    "id": "14yy74hwogxoyl2l3v"

iso_codename 已转换为 null

有人可以帮我吗?看不懂。

我正在使用 Python 2.7 和 Spark 2.0.0

谢谢!

【问题讨论】:

感谢您以严谨且可重复的方式提出您的第一个 SO 问题(不幸的是,对于新用户来说这很不寻常)。继续接受和支持好的答案(这会占用受访者的宝贵时间)... 【参考方案1】:

按照@user6910411 已经提供的解释(并节省我自己做的时间),补救措施(即中间JSON 表示)是使用read.json 而不是toDF 和你的函数:

spark.version
# u'2.0.2'

jsonRDD = sc.parallelize(["id": "14yy74hwogxoyl2l3v", "geoloc": "country": "geoname_id": 3017382, "iso_code": "FR", "name": "France"])

df = spark.read.json(jsonRDD)
df.collect()
# result:
[Row(geoloc=Row(country=Row(geoname_id=3017382, iso_code=u'FR', name=u'France')), id=u'14yy74hwogxoyl2l3v')]

# just to have a look at what will be saved:
df.toJSON().collect()
# result:
[u'"geoloc":"country":"geoname_id":3017382,"iso_code":"FR","name":"France","id":"14yy74hwogxoyl2l3v"']

df.toJSON().saveAsTextFile("/tmp/json.test")

作为比较,这是您自己的 df2 的外观:

df2.collect()
# result:
[Row(geoloc=u'country': u'geoname_id': 3017382, u'iso_code': None, u'name': None, id=u'14yy74hwogxoyl2l3v')]

df2.toJSON().collect()
# result:
[u'"geoloc":"country":"name":null,"iso_code":null,"geoname_id":3017382,"id":"14yy74hwogxoyl2l3v"']

【讨论】:

【参考方案2】:

发生这种情况是因为您没有正确使用RowRow 构造函数不是递归的,只对***字段进行操作。当您查看架构时:

root
 |-- geoloc: map (nullable = true)
 |    |-- key: string
 |    |-- value: map (valueContainsNull = true)
 |    |    |-- key: string
 |    |    |-- value: long (valueContainsNull = true)
 |-- id: string (nullable = true)

您会看到geoloc 表示为map<string,struct<string,long>>。结构的正确表示将使用嵌套的Rows

Row(
    id="14yy74hwogxoyl2l3v", 
    geoloc=Row(
        country=Row(geoname_id=3017382, iso_code="FR", name="France")))

而你传递的相当于:

Row(
    geoloc='country': 
        'geoname_id': 3017382, 'iso_code': 'FR', 'name': 'France', 
        id='14yy74hwogxoyl2l3v')

由于创建正确的实现必须涵盖许多边界情况,因此使用中间 JSON 表示和 Spark JSON 数据源会更有意义。

【讨论】:

以上是关于Pyspark - 将rdd转换为数据框时数据设置为null的主要内容,如果未能解决你的问题,请参考以下文章

Pyspark 将 rdd 转换为具有空值的数据帧

将 numpy 数组的 rdd 转换为 pyspark 数据帧

使用 pyspark 将 RDD 行转换为数据帧时出错

PySpark:将 RDD 转换为数据框中的列

将 Pyspark RDD 转换为 Pandas 数据框

Pyspark:由于数据类型 str 而不是 StringType,无法将 RDD 转换为 DataFrame