我需要一些帮助才能将S3存储桶中的一系列JSON文件存入PySpark DataFrame。
此存储桶中的文件都有.json
扩展名,但遗憾的是不遵守通常的Spark要求,即每行有一个JSON对象,而是在方括号内的所有行中。 / p>
所以而不是:
{"first_column": 12, "second_column": {"nested_column": "value"}}
{"first_column": 24, "second_column": {"nested_column": "value2"}}
我有:
[{"first_column": 12, "second_column": {"nested_column": "value"}},{"first_column": 24, "second_column": {"nested_column": "value2"}}]
我们实际上收到了这种格式的文件,并且有很多这样的文件,不幸的是不可能进行任何手动调整。
到目前为止,我尝试过的方法如下:
我尝试使用spark.read.json
方法,使用以下语法与通配符*
一起加载多个文件。在这种情况下,spark
是sqlContext
df = spark.read.json("s3://path_to_bucket_*.json")
运行时不会引发任何错误或警告,并返回所需的架构:
df.printSchema()
root
|-- first_column: long (nullable = true)
|-- second_column: struct (nullable = true)
| |-- nested_column: string (nullable = true)
但是,当我尝试查看数据时,我得到以下内容:
+------------+-------------+
|first_column|second_column|
+------------+-------------+
| null| null|
+------------+-------------+
我找到了一种从Databricks here实际加载数据的方法,它使用Spark上下文sc
来读取配对RDD,如下所示:
dfRDD = sc.wholeTextFiles("s3://path_to_bucket_*.json")
这将返回带有文件名和文件正文的PairedRDD。然而,让我感到困惑的是,当我使用来自此RDD的正文信息调用以下行时,它工作正常并且根本没有空值:
df = spark.read.json(dfRDD.map(lambda x: x[1]))
所以,我很困惑为什么会发生这种情况,因为我认为这是相同的信息被输入函数,因为RDD中的文本正文不包含任何换行符,而是包含方括号内的JSON对象(就像我上面显示的第二个例子)。
虽然这是一种解决方法,但遗憾的是缺乏这种方法;首先,使用RDD方法要慢得多,更重要的是,我需要获取我从中获取此信息的文件名的列。我知道当从文件直接加载时,使用input_file_name
模块中的pyspark.sql.functions
函数可以实现这一点,但是在使用RDD方法时这不起作用。我设法编写了一个纯Python函数,它将每个配对RDD的第一个元素的文件名信息转换为JSON字符串,但这很慢。
如果有人能帮我解决这个问题,我将非常感激。我很欣赏我可能不得不使用RDD方法,但我很困惑为什么spark.read.json
在一种情况下完美运行,而不是另一种情况。
答案 0 :(得分:1)
虽然我不确定是什么导致一个解决方案工作而另一个解决方案没有,但是我能够通过仅使用sql.read.json在某种程度上解决问题。
将read.json中的参数allowComments,allowUnquotedFieldNames,allowSingleQuotes,allowNumericLeadingZero,allowBackslashEscapingAnyCharacter设置为True。通过这种方式,我能够删除空值,并且在数据帧中成功转换了90%的数据而没有任何空值。
查看其他参数here