如何使用pyspark为1000个文件将文件中的Header值作为csv文件中的额外列附加

时间:2017-08-31 16:00:28

标签: python apache-spark pyspark

我一直在尝试使用 #Id 过滤掉标题行,并将id number作为列添加到正在处理的 file_name 。以下是要处理的示例文件

文件1:

#sample first line
#Id: abcdef
col1,col2,col3
1,2,3
2,3,3
4,5,6

文件2:

#sample first line
#Id: ghjklo
col1,col2,col3
5,1,3
2,5,8
8,0,4

当我尝试构建数据框并打印结果时,我可以使用下面的代码段将文件名添加为列。

par_df = spark.read.schema(schema) \
                    .option("header", "true") \
                    .format("com.databricks.spark.csv") \
                    .option("mode", "DROPMALFORMED")\
                    .csv("s3a://" + bucket "/"+prefix+"/").withColumn("FileName", func.input_file_name())

这会过滤掉标题信息,下面是打印结果的代码段。

parsed_diff_df = par_df.select(
    par_df['col1'],
    par_df['col2'])    
parsed_diff_df.registerTempTable("parsed_diff_df_table")
results = sqlContext.sql("select col1, col2, FileName from "                        
                             "parsed_diff_df_table").collect()

这是我得到的结果,无法附加Id列,因为它已经过滤掉了。

1,2,3,File1
2,3,3,File1
4,5,6,File1
5,1,3,File2
2,5,8,File2
8,0,4,File2

预期结果如下。

1,2,3,abcdef,File1
2,3,3,abcdef,File1
4,5,6,abcdef,File1
5,1,3,ghjklo,File2
2,5,8,ghjklo,File2
8,0,4,ghjklo,File2

我也试过这个,但没有运气。

   rdd = sc.textFile("s3a://" + bucket + "/"+prefix+"/").flatMap(lambda line: line.split("\n")).filter(lambda line: '#' in line)

   results = rdd.collect()
   for row in results:
       print row

2 个答案:

答案 0 :(得分:2)

您可以将每个文件的FileName映射到id

让我们编写一个函数来提取id值:

import re
def extract_id(l):
    return re.search('#Id: ([a-z]+)\\n', line).group(1)

让我们将文件读作RDD:

file_id = sc.wholeTextFiles("/user/at967214/test.csv").filter(lambda l: l[1][0]=='#').map(lambda l: [l[0], extract_id(l[1])])

现在是数据框:

file_id_df = spark.createDataFrame(file_id, ["FileName", "id"])

现在您可以将其加入第一个数据框

par_df.join(file_id_df, "FileName", "inner")

答案 1 :(得分:1)

不使用csv loader,而是实现以下步骤来实现:

  • 使用sparkContext.wholeTextFiles将数据加载到rdd对。
  • 应用flatMapValues函数
    1. 使用新行'\ n'
    2. 拆分每条记录
    3. 从第一行获取id - >使用':'拆分第一行,然后将split的第二部分作为id。
    4. 在预定义架构时跳过第二行。
    5. 第3行到最后一行追加id。
  • 应用地图功能跳过键,因为它包含文件名和拆分值到各列 - >使用','拆分。
  • 使用'col1,col2,col3'
  • 将RDD转换为数据集

我是java开发人员,对Python没有多少帮助,类似的东西可能对你有帮助:

pairRdd=sc.wholeTextFiles('<path>')

#it exactly wont work, make required changes:
def appendId( record ):
   splits = record.splitlines()
   id=splits[0].split(':')[1].strip()
   print(id)
   output=[]
   for s in xrange(2,len(splits)):
       output.append(splits[s]+','+id)
   return output
objRDD=pairRdd.flatMapValues(appendId)
.map(lambda key,val:val.split(','))
.map(lambda p:Row(col1=int(p[0]), col2=int(p[1])........FileName=p[3]))
dataframe=spark.createDataFrame(objRdd)
.....

等效Java:

JavaPairRDD<String[]> inputRdd = sparkContext.wholeTextFiles("<xyz path>");;
    inputRdd.flatMapValues(new Function<String, Iterable<String>>() {
                               @Override
                               public Iterable<String> call(String v1) throws Exception {
                                   String[] splits = v1.split( System.getProperty("line.separator"));
                                   String id = splits[0].split(":")[1].trim();
                                   List<String> values = new ArrayList<String>();
                                   for (int i =2;i<splits.length;i++){
                                       values.add(String.format("%s,%s", splits[i],id));
                                   }
                                   return values;
                               }
                           }
    ).map(s->s._2().split(","));