【问题标题】:Pyspark - Data set to null when converting rdd to dataframePyspark - 将rdd转换为数据框时数据设置为null
【发布时间】: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 问题(不幸的是,对于新用户来说这很不寻常)。继续接受和支持好的答案(这会占用受访者的宝贵时间)...

标签: python apache-spark pyspark apache-spark-sql


【解决方案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 数据源会更有意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-08
      • 1970-01-01
      相关资源
      最近更新 更多