PySpark:如何读取许多JSON文件,每个文件多个记录

时间:2015-02-23 23:55:10

标签: json amazon-s3 apache-spark pyspark

我有一个存储在S3存储桶中的大型数据集,但它不是一个大型文件,而是由许多(113K准确)单个JSON文件组成,每个文件包含100-1000个观察值。这些观察结果不是最高级别,但需要在每个JSON中进行一些导航才能访问。 即 json [" interaction"]是一个词典列表。

我试图利用Spark / PySpark(版本1.1.1)来解析并减少这些数据,但我无法找到将其加载到RDD的正确方法,因为它&# 39; s并非所有记录>一个文件(在这种情况下我使用sc.textFile,虽然在这里添加了JSON的复杂功能),也没有每个记录>一个文件(在这种情况下,我使用sc.wholeTextFiles)。

我最好选择使用sc.wholeTextFiles然后使用地图(或者在这种情况下使用flatMap?)将多个观察结果从单个文件名密钥存储到自己的密钥中?或者有一种更简单的方法来做到这一点,我错过了吗?

我在这里看到的答案建议只在通过sc.textFile加载的所有文件上使用json.loads(),但它似乎并不适用于我,因为JSON不是。简单的最高级别列表。

3 个答案:

答案 0 :(得分:7)

以前的答案不会以分布式方式读取文件(请参阅reference)。为此,您需要并行化s3键,然后在flatMap步骤中读取文件,如下所示。

import boto3
import json
from pyspark.sql import Row

def distributedJsonRead(s3Key):
    s3obj = boto3.resource('s3').Object(bucket_name='bucketName', key=s3Key)
    contents = json.loads(s3obj.get()['Body'].read().decode('utf-8'))
    for dicts in content['interactions']
        yield Row(**dicts)

pkeys = sc.parallelize(keyList) #keyList is a list of s3 keys
dataRdd = pkeys.flatMap(distributedJsonRead)

Boto3 Reference

答案 1 :(得分:5)

使用DataFrames怎么样?

确实 testFrame = sqlContext.read.json('s3n://<bucket>/<key>') 从一个文件中找到你想要的东西?

每个观察都有相同的&#34;列&#34; (键数#)?

如果是这样,你可以使用boto列出你想要添加的每个对象,读取它们并将它们相互联合起来。

from pyspark.sql import SQLContext
import boto3
from pyspark.sql.types import *
sqlContext = SQLContext(sc)

s3 = boto3.resource('s3')
bucket = s3.Bucket('<bucket>')

aws_secret_access_key = '<secret>'
aws_access_key_id = '<key>'

#Configure spark with your S3 access keys
sc._jsc.hadoopConfiguration().set("fs.s3n.awsAccessKeyId", aws_access_key_id)
sc._jsc.hadoopConfiguration().set("fs.s3n.awsSecretAccessKey", aws_secret_access_key)
object_list = [k for k in bucket.objects.all() ]
key_list = [k.key for k in bucket.objects.all()]

paths = ['s3n://'+o.bucket_name+'/'+ o.key for o in object_list ]

dataframes = [sqlContext.read.json(path) for path in paths]

df = dataframes[0]
for idx, frame in enumerate(dataframes):
    df = df.unionAll(frame)

我是新手,所以我想知道是否有更好的方法将数据帧与大量s3文件一起使用,但到目前为止这对我有用。

答案 2 :(得分:3)

该名称具有误导性(因为它是单数),但sparkContext.textFile()(至少在Scala案例中)也接受目录名称或通配符路径,因此您只能说textFile("/my/dir/*.json")