将具有不同列顺序和字段名的多个CSV文件读入Spark

时间:2017-10-05 17:06:03

标签: python pyspark-sql

我有一个CSV文件目录,我想读入Spark数据帧。我知道当文件具有相同的字段名和列顺序时,这是直截了当的:

raw_transactions_df = spark.read.csv("file_*.csv", inferSchema=True, header=True)

但是,由于我的文件来自不同的系统:

  • 他们没有相同的列顺序。
  • 其中一个字段名称在某些文件中拼写不同

在这种情况下,是否有一种干净的方法可以将一个目录中的所有csv文件加载到一个公共的火花数据帧中,并以可重复的方式进行?

我的第一次尝试如下:

import csv

final_headers = ['col1', 'col2', 'col3', 'col4', 'col5', 'col6', 'col7']

merged_rows = []
for f in trans_files:
    with open(f, 'r') as csv_in:
        csvreader = csv.reader(csv_in, delimiter=',')
        headers = dict((h, i) for i, h in enumerate(next(csvreader)))
        headers = { x.replace('col7_id', 'col7'): headers[x] for x in headers.keys() }

        for row in csvreader:
            merged_rows.append(tuple(row[headers[x]] for x in final_headers))

merged_df = spark.createDataFrame(merged_rows, final_headers)

这在某种程度上起作用 - 但会产生DF,其中所有列都是StringType。如果我尝试将定义的模式传递给spark.createDataFrame,我最终会遇到异常:

TypeError: DecimalType(16,0) can not accept object '83215400105' in type <class 'str'>

编辑:我知道我可以根据需要和快乐日明确地投射我的专栏 - 但是如果我们遇到另一个列顺序或错误拼写的列名,所有这些看起来都非常容易破解。

那么 - 是否有一个很好的策略可以用来将CSV从目录加载到Spark中,并且我已经在上面指定了哪些挑战?

1 个答案:

答案 0 :(得分:0)

是的,你可以

  1. 如果行的顺序不同,但是您在标题中具有行名(由于您使用的是header=True,所以我假设只是读取它们。一旦进入数据框上下文,底层顺序无关紧要,因为无论如何您都按名称寻址行

  2. 在特定情况下(行名不同),这些行的col7为空,col7_id可以通过SQL在邮寄中固定。

    < / li>

如果由于某种原因无法读取整个目录,只需遍历所有文件,在循环中创建DF并使用df.union -function,那么您甚至可以处理{{1} }有