如何将PythonRDD(JSON中的行)转换为DataFrame?

时间:2016-06-05 02:11:10

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

我正在尝试读取多个JSON来创建DataFrame。

我将多个JSON文件放在一个PythonRDD中,然后当我尝试转换为DataFrame时,它失败了。我使用方法toDF()sqlContext.createDataFrame()我收到以下错误:

ValueError: Some of types cannot be determined by the first 100 rows, please try again with sampling

这很奇怪,因为使用sqlContext.read.json()可以正常工作。

这是我的代码:

import json
from pyspark.sql import Row

def dict_to_row(obj):
    if isinstance(obj, dict) and len(obj.values())>0:
        d = {}
        for k in obj.keys():
            d[k] = dict_to_row(obj[k])
            return Row(**d)
    elif isinstance(obj, list):
        return [dict_to_row(o) for o in obj]
    else:
        return obj

def distributed_json_read(filename):
    jsons = open(filename,'r')
    json_list = jsons.readlines()
    for e in json_list:
        json_row = json.loads(e.rstrip())
        yield dict_to_row(json_row)

json_list = ['test1.json','test2.json']
parallel_keys = sc.parallelize(json_list)
data_rdd = parallel_keys.flatMap(distributed_json_read)
df = sqlContext.createDataFrame(data_rdd)

这是test1.json的一个例子:

{
    "data": {
        "f": {
            "a": {
                "a1": 100,
                "a2": 1
            },
            "b": [
                {
                    "b1": {
                        "b11": 1,
                        "b12": null
                    },
                    "date1": "2016-02-05T01:58:04.000-0400",
                    "b2": {
                        "b21": null,
                        "b22": "9ca6d130fddb",
                        "b23": false
                    }
                }
            ]
        }
    },
    "id": 1689
}

有人遇到此错误?

实际上我的目标是读取多个可能具有不同模式的JSON文件,但最后构建一个DataFrame,其模式将是JSON模式的并集。与sqlContext.read.json()相似,如果参数是一个内置多个JSON的文件。

3 个答案:

答案 0 :(得分:1)

我之前写了一个自定义的json阅读器来获得火花。我在包含json文件的文件夹上使用了sc.wholeTextFiles()或sc.binaryFiles()。

这将给你一个rdd(k,v)(file_url,wholeFile / BinaryFile) 然后你可以在那个rdd

上申请你的平面地图


rdd = sc.wholeTextFiles(“super_folder_containing_jsons”)
data_rdd = rdd.flatMap(distributed_json_read)
df = sqlContext.createDataFrame(data_rdd)

答案 1 :(得分:0)

您可以为数据框提供静态模式(所有类型的超集),或者为代码提供第一个json以及有助于拥有默认模式的所有字段。

当你没有默认模式而你给json(字段较少)时会出现一个问题,以后可能会因为使用新字段读取新的json文件而出现问题。

答案 2 :(得分:0)

Spark中的JSON必须是单行的,即单个JSON文件应该是一行。

scala> final case class Token(id: Int, body: String)
defined class Token

scala> val df = spark.createDataset(Seq(Token(0, "hello"), Token(1, "world")))
df: org.apache.spark.sql.Dataset[Token] = [id: int, body: string]

scala> df.show
+---+-----+
| id| body|
+---+-----+
|  0|hello|
|  1|world|
+---+-----+

scala> df.write.json("so.json")

// $ cat so.json/part-r-00003-469964b4-aaf8-4c7a-8f8a-d76c08e792ce.json
// {"id":0,"body":"hello"}