结构化流 - 将json字段分解为动态列?

时间:2018-01-31 09:39:15

标签: apache-spark pyspark spark-structured-streaming

我从Kafka来源获得了这个数据帧。

+-----------------------+
|         data          |
+-----------------------+
| '{ "a": 1, "b": 2 }'  |
+-----------------------+
| '{ "b": 3, "d": 4 }'  |
+-----------------------+
| '{ "a": 2, "c": 4 }'  |
+-----------------------+

我想将其转换为以下数据框:

+---------------------------+
|  a   |  b   |  c   |  d   |
+---------------------------+
|  1   |  2   | null | null |
+---------------------------+
| null |  3   | null |  4   |
+---------------------------+
|  2   | null |  4   | null |
+---------------------------+

JSON字段数可能会更改,因此我无法为其指定架构。

我几乎了解了如何在spark批处理中进行转换,使用一些map和reduce来获取一组JSON键,然后使用withColumns构建新的数据帧。

然而,据我所知,结构化流媒体中没有地图缩减功能。我如何实现这一目标?

更新

我发现UDF可用于解析字符串到JSON字段

import simplejson as json
from pyspark.sql.functions import udf

def convert_json(s):
   return json.loads(s)

udf_convert_json = udf(convert_json, StructType(<..some schema here..>))
df = df.withColumn('parsed_data', udf_convert_json(df.data))

但是由于模式是动态的,我需要在df.data中获取所有JSON键和值一段窗口期,以构造udf返回类型中使用的StructType。

最后,我想我需要知道如何在某个窗口期间为数据集执行reduce,然后将其用作流转换中的查找模式。

2 个答案:

答案 0 :(得分:1)

如果您已经知道json数据中的所有唯一键,那么我们可以使用json_tuple函数,

>>> df.show()
+------------------+
|              data|
+------------------+
|{ "a": 1, "b": 2 }|
|{ "b": 3, "d": 4 }|
|{ "a": 2, "c": 4 }|
+------------------+
>>> from pyspark.sql import functions as F
>>> df.select(F.json_tuple(df.data,'a','b','c','d')).show()
+----+----+----+----+
|  c0|  c1|  c2|  c3|
+----+----+----+----+
|   1|   2|null|null|
|null|   3|null|   4|
|   2|null|   4|null|
+----+----+----+----+

>>> from pyspark.sql.types import *
>>> schema = StructType([StructField("a", StringType()),StructField("b", StringType()),StructField("c",StringType()),StructField("d", StringType())])
>>> df.select(F.from_json(df.data,schema).alias('data')).select(F.col('data.*')).show()
+----+----+----+----+
|   a|   b|   c|   d|
+----+----+----+----+
|   1|   2|null|null|
|null|   3|null|   4|
|   2|null|   4|null|
+----+----+----+----+

答案 1 :(得分:-1)

我想,你不需要做太多。例如,

Bala:~:$ cat myjson.json 
{ "a": 1, "b": 2 }
{ "b": 3, "d": 4 }
{ "a": 2, "c": 4 }

>>> df = sqlContext.sql("select * from json.`/Users/Bala/myjson.json`")
>>> df.show()
+----+----+----+----+
|   a|   b|   c|   d|
+----+----+----+----+
|   1|   2|null|null|
|null|   3|null|   4|
|   2|null|   4|null|
+----+----+----+----+