使用Spark从JSON解析字典数组

时间:2018-08-22 05:39:37

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

有一个可以用JSON响应的市场营销API,如下所示:

{'page': 1,
 'total_pages': 1,
 'data': [
   {'day': '2018-06-11',
     'spend': 84.0,
     'clicks': 428,
     'impressions': 14778},
   {'day': '2018-06-12',
     'spend': 10.0,
     'clicks': 18,
     'impressions': 1778}
  ]
}

我想要一个这样的数据框:

+----------+-----+------+-----------+
|       day|spend|clicks|impressions|
+----------+-----+------+-----------+
|2018-06-11| 84.0|   428|      14778|
|2018-06-12| 10.0|    18|       1778|
+----------+-----+------+-----------+

在常规python中,我可以这样做:

response = requests.get(url).json()
df = pd.DataFrame(response['data'])

但是该解决方案必须在AWS Glue中有效,并且Pandas不受欢迎。一整天的搜索一直没有结果。一些亮点:

许多建议首先将其并行化,然后将RDD转换为数据帧:

response = requests.get(url).json()
rdd = sc.parallelize(response)
df = rdd.toDF()

但这会导致:

  

TypeError:无法推断类型的模式:

其他人说这应该见效:

response = requests.get(url)
df = sqlContext.createDataFrame([json.loads(line) for line in response.iter_lines()])

但是它导致了这个数据帧,它阻止了所有解析尝试:

root
 |-- data: array (nullable = true) 
 |    |-- element: map (containsNull = true)
 |    |    |-- key: string
 |    |    |-- value: string (valueContainsNull = true)
 |-- page: long (nullable = true)
 |-- total_pages: long (nullable = true)

+--------------------+----+-----------+
|                data|page|total_pages|
+--------------------+----+-----------+
|[Map(impressions ...|   1|          1|
+--------------------+----+-----------+

1 个答案:

答案 0 :(得分:0)

看来您已经解决了。在摘要中

response = requests.get(url).json()
rdd = sc.parallelize(response)
df = rdd.toDF()

response是一个嵌套的JSON对象,因此数据框无法以某种方式推断出架构。根据我的理解,您不需要整个响应对象的架构。您正在寻找的只是data对象的response字段。

因此,以下代码段以预期的格式加载数据:

response = requests.get(url).json()
rdd = sc.parallelize(response['data'])
df = rdd.toDF()

您的第二种方法中也存在相同的问题。 另外,在使用createDataFrame创建数据帧时,您无需再次加载line,因为它已经是一个json / dict对象。 下面的代码段应该可以工作:

response = requests.get(url).json()
df = sqlContext.createDataFrame([line for line in response['data']])