读取文件并将其附加到Spark数据框中

时间:2019-09-06 14:33:54

标签: pyspark

我已经创建了一个空的数据框,并通过读取每个文件开始将其添加到其中。但是其中一个文件的列数比以前的多。如何仅选择第一个文件中所有其他文件的列?

from pyspark.sql import SparkSession

from pyspark.sql import SQLContext

from pyspark.sql.types import StructType
import os, glob
spark = SparkSession.builder.\           
    config("spark.jars.packages","saurfang:spark-sas7bdat:2.0.0-s_2.11")\            
    .enableHiveSupport().getOrCreate()
fpath=''
schema = StructType([])
sc = spark.sparkContext
df_spark=spark.createDataFrame(sc.emptyRDD(), schema)
files=glob.glob(fpath +'*.sas7bdat')
for i,f in enumerate(files):
    if i == 0:
       df=spark.read.format('com.github.saurfang.sas.spark').load(f)   
       df_spark= df
    else:
         df=spark.read.format('com.github.saurfang.sas.spark').load(f) 
         df_spark=df_spark.union(df)

2 个答案:

答案 0 :(得分:1)

您可以从第一个文件的架构中获取字段名,然后使用字段名数组从所有其他文件中选择列。

fields = df.schema.fieldNames

您可以使用fields数组从所有其他数据集中选择列。以下是用于此的scala代码。

df=spark.read.format('com.github.saurfang.sas.spark').load(f).select(fields(0),fields.drop(1):_*)

答案 1 :(得分:1)

您可以在创建数据框时提供自己的架构。 例如,我有两个具有不同架构的文件emp1.csv & emp2.csv

id,empname,empsalary
1,Vikrant,55550

id,empname,empsalary,age,country
2,Raghav,10000,32,India

schema = StructType([
            StructField("id", IntegerType(), True),
            StructField("name", StringType(), True),
            StructField("salary", IntegerType(), True)])

file_path="file:///home/vikct001/user/vikrant/inputfiles/testfiles/emp*.csv"
df=spark.read.format("com.databricks.spark.csv").option("header", "true").schema(schema).load(file_path)

指定架构不仅可以解决数据类型和格式问题,而且还必须提高性能。

如果您需要删除格式不正确的记录,则还有其他选项,但是这也会删除具有空值或不符合所提供模式的记录。 它可能会跳过那些具有多个定界符和垃圾字符或空文件的记录。

.option("mode", "DROPMALFORMED")

FAILFAST模式将在发现格式错误的记录时引发异常。

.option("mode", "FAILFAST")

您还可以使用地图功能选择所需的元素,并在构建数据框时排除其他元素。

df=spark.read.format('com.databricks.spark.csv').option("header", "true").load(file_path).rdd.map(lambda x :(x[0],x[1],x[2])).toDF(["id","name","salary"])

在两种情况下,您都需要将标头设置为“ true”,否则它将包含csv标头作为数据框的第一条记录。