如何在pyspark中读取多层json?

时间:2018-12-18 16:57:05

标签: apache-spark pyspark

**Json Structure is -:**
aa.json

[[{"foo":"test1"},{"foo1":"test21"}],
[{"foo":"test2"},{"foo1":"test22"}],
[{"foo":"test3"},{"foo1":"test23"}]]

读取DataFrame的代码:

from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)

a=sqlContext.read.option('multiline',"true").json('aa.json');
a.show()
+----+----+
| foo|foo1|
+----+----+
|null|null|
+----+----+

a.printSchema()
root
 |-- foo: string (nullable = true)
 |-- foo1: string (nullable = true)

这里是读取此json的行,它可以解析架构,但不能解析数据。

1 个答案:

答案 0 :(得分:1)

应用一些正则表达式并将其转换为rdd可能对您有用。

首先使用textFile读取文件:

a=spark.read.option('multiline',"true").text('aa.json')
a.show(truncate=False)
#+-------------------------------------+
#|value                                |
#+-------------------------------------+
#|[[{"foo":"test1"},{"foo1":"test21"}],|
#|[{"foo":"test2"},{"foo1":"test22"}], |
#|[{"foo":"test3"},{"foo1":"test23"}]] |
#+-------------------------------------+

现在,我们可以使用pyspark.sql.functions.regexp_replace删除每行中多余的方括号和结尾的逗号:

from pyspark.sql.functions import regexp_replace
a = a.select(regexp_replace("value", "(^\[(?=\[))|((?<=\])\]$)|(,$)", "").alias("value"))
a.show(truncate=False)
#+-----------------------------------+
#|value                              |
#+-----------------------------------+
#|[{"foo":"test1"},{"foo1":"test21"}]|
#|[{"foo":"test2"},{"foo1":"test22"}]|
#|[{"foo":"test3"},{"foo1":"test23"}]|
#+-----------------------------------+

此处的模式是逻辑模式或以下模式:

  • ^\[(?=\[):字符串开头,后跟[[(第二个[是非捕获组)
  • (?<=\])\]$:位于字符串末尾的]](第一个]是一个非捕获组)
  • ,$:字符串末尾的逗号

任何匹配的模式都将替换为空字符串。

现在转换为rdd并使用json.loads将行解析为字典列表。然后merge all of these dictionaries together into one dictionary并调用pyspark.sql.Row构造函数。最后调用.toDF以转换回DataFrame。

# From `How to merge two dictionaries in a single expression?`
# This code works for python 2 and 3
def merge_two_dicts(x, y):
    z = x.copy()   # start with x's keys and values
    z.update(y)    # modifies z with y's keys and values & returns None
    return z

import json
from pyspark.sql import Row
from functools import reduce 

a.rdd.map(lambda x: Row(**reduce(merge_two_dicts, json.loads(x['value'])))).toDF().show()
#+-----+------+
#|  foo|  foo1|
#+-----+------+
#|test1|test21|
#|test2|test22|
#|test3|test23|
#+-----+------+

参考