使用pySpark和云存储过滤数百万个文件

使用pySpark和云存储过滤数百万个文件,pyspark,google-cloud-storage,google-cloud-dataproc,Pyspark,Google Cloud Storage,Google Cloud Dataproc,我面临着以下任务:我将单个文件(如Mb)存储在Google云存储桶中,按日期分组在目录中(每个目录包含大约5k个文件)。我需要查看每个文件(xml),过滤适当的文件并将其放入Mongo或以拼花格式写回Google云存储。我编写了一个简单的pySpark程序,如下所示: import pyspark from pyspark.sql import SparkSession from pyspark.sql.types import * spark = ( SparkSession

我面临着以下任务:我将单个文件(如Mb)存储在Google云存储桶中,按日期分组在目录中(每个目录包含大约5k个文件)。我需要查看每个文件(xml),过滤适当的文件并将其放入Mongo或以拼花格式写回Google云存储。我编写了一个简单的pySpark程序,如下所示:

import pyspark
from pyspark.sql import SparkSession
from pyspark.sql.types import *

spark = (
    SparkSession
    .builder
    .appName('myApp')
    .config("spark.mongodb.output.uri", "mongodb://<mongo_connection>") 
    .config("spark.mongodb.output.database", "test") 
    .config("spark.mongodb.output.collection", "test")
    .config("spark.hadoop.google.cloud.auth.service.account.enable", "true")
    .config("spark.dynamicAllocation.enabled", "true")
    .getOrCreate()
)

spark_context = spark.sparkContext
spark_context.setLogLevel("INFO")
sql_context   = pyspark.SQLContext(spark_context)

# configure Hadoop
hadoop_conf = spark_context._jsc.hadoopConfiguration()
hadoop_conf.set("fs.gs.impl", "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem")
hadoop_conf.set("fs.AbstractFileSystem.gs.impl", "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS")


# DataFrame schema
schema = StructType([
    StructField('filename', StringType(), True),
    StructField("date", DateType(), True),
    StructField("xml", StringType(), True)
])

# -------------------------
# Main operation
# -------------------------
# get all files
files = spark_context.wholeTextFiles('gs://bucket/*/*.gz')

rows = files \
    .map(lambda x: custom_checking_map(x)) \
    .filter(lambda x: x is not None)

# transform to DataFrame 
df = sql_context.createDataFrame(rows, schema)

# write to mongo
df.write.format("mongo").mode("append").save()

# write back to Cloud Storage
df.write.parquet('gs://bucket/test.parquet')

spark_context.stop()
导入pyspark
从pyspark.sql导入SparkSession
从pyspark.sql.types导入*
火花=(
SparkSession
建设者
.appName('myApp')
.config(“spark.mongodb.output.uri”,“mongodb://”)
.config(“spark.mongodb.output.database”,“test”)
.config(“spark.mongodb.output.collection”、“test”)
.config(“spark.hadoop.google.cloud.auth.service.account.enable”,“true”)
.config(“spark.dynamicAllocation.enabled”、“true”)
.getOrCreate()
)
spark\u context=spark.sparkContext
spark_context.setLogLevel(“信息”)
sql\u context=pyspark.SQLContext(spark\u context)
#配置Hadoop
hadoop\u conf=spark\u context.\u jsc.hadoopConfiguration()
hadoop_conf.set(“fs.gs.impl”、“com.google.cloud.hadoop.fs.gcs.GoogleHadoop文件系统”)
hadoop_conf.set(“fs.AbstractFileSystem.gs.impl”、“com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS”)
#数据帧模式
schema=StructType([
StructField('filename',StringType(),True),
StructField(“日期”,DateType(),True),
StructField(“xml”,StringType(),True)
])
# -------------------------
#主要业务
# -------------------------
#获取所有文件
files=spark\u context.wholeTextFiles('gs://bucket/*/*.gz'))
行=文件\
.map(lambda x:自定义检查映射(x))\
.过滤器(λx:x不是无)
#转换为数据帧
df=sql\u context.createDataFrame(行,模式)
#写信给mongo
df.write.format(“mongo”).mode(“append”).save()
#写回云存储
df.write.parquet('gs://bucket/test.parquet')
spark_context.stop()
我在一个子集(单个目录
gs://bucket/20191010/*.gz
)上测试了它,它运行正常。我在Google Dataproc集群上部署了它,但我怀疑日志在
19/11/06 15:41:40 INFO org.apache.hadoop.warn.client.api.impl.YarnClientImpl:提交的应用程序\u 1573054807908\u 0001之后是否会发生任何事情

我运行的是3个工作集群,有4个内核和15GB RAM+500GB硬盘。Spark版本2.3.3,scala 2.11 mongo-connector-Spark_2.11-2.3.3。
我是新的火花,所以任何建议都很感谢。通常情况下,我会使用Python多处理来编写这项工作,但我想做一些“更好”的事情,但现在我不确定。

在GCS中列出大量文件可能需要花费大量时间—很可能是在Spark驱动程序在开始处理之前列出所有文件时,您的工作“挂起”

通过先列出所有目录,然后再处理每个目录中的文件,您将获得更好的性能-为了获得最佳性能,您可以并行处理目录,但考虑到每个目录有5k个文件,并且您的群集只有3个工作进程,按顺序处理目录就足够了