在Apache Beam中读取CSV文件时跳过标题

时间:2018-06-14 10:45:59

标签: java google-cloud-platform google-cloud-dataflow apache-beam

我想跳过CSV文件中的标题行。截至目前,我在将其加载到谷歌存储之前手动删除标题。

以下是我的代码:

PCollection<String> financeobj =p.apply(TextIO.read().from("gs://storage_path/Financials.csv"));        
    PCollection<ClassFinance> pojos5 = financeobj.apply(ParDo.of(new DoFn<String, ClassFinance>() { // converting String into classtype

        private static final long serialVersionUID = 1L;
        @ProcessElement
        public void processElement(ProcessContext c) {
            String[] strArr = c.element().split(",");
            ClassFinance fin = new ClassFinance();
            fin.setBeneficiaryFinance(strArr[0]);
            fin.setCatlibCode(strArr[1]);
            fin.set_rNR_(Double.valueOf(strArr[2]));
            fin.set_rNCS_(Double.valueOf(strArr[3]));
            fin.set_rCtb_(Double.valueOf(strArr[4]));
            fin.set_rAC_(Double.valueOf(strArr[5]));
            c.output(fin);
        }
    }));

我已经检查了stackoverflow中的现有问题,但我发现它很有希望:Skipping header rows - is it possible with Cloud DataFlow?

任何帮助?

编辑:我尝试了类似下面的内容并且有效:

PCollection<String> financeobj = p.apply(TextIO.read().from("gs://google-bucket/final_input/Financials123.csv"));       

    PCollection<ClassFinance> pojos5 = financeobj.apply(ParDo.of(new DoFn<String, ClassFinance>() { // converting String into classtype

        private static final long serialVersionUID = 1L;
        @ProcessElement
        public void processElement(ProcessContext c) {  
            String[] strArr2 = c.element().split(",");
            String header = Arrays.toString(strArr2);
            ClassFinance fin = new ClassFinance();

                if(header.contains("Beneficiary"))
                System.out.println("Header");
                else {
            fin.setBeneficiaryFinance(strArr2[0].trim());
            fin.setCatlibCode(strArr2[1].trim());
            fin.setrNR(Double.valueOf(strArr2[2].trim().replace("", "0")));
            fin.setrNCS(Double.valueOf(strArr2[3].trim().replace("", "0")));
            fin.setrCtb(Double.valueOf(strArr2[4].trim().replace("", "0")));
            fin.setrAC(Double.valueOf(strArr2[5].trim().replace("", "0")));
            c.output(fin);
            }
        }
    }));

3 个答案:

答案 0 :(得分:2)

此代码对我有用。我已经使用Filter.by()从csv文件中过滤出标题行。

static void run(GcsToDbOptions options) {

Pipeline p = Pipeline.create(options);
// Read the CSV file from GCS input file path
p.apply("Read Rows from " + options.getInputFile(), TextIO.read()
    .from(options.getInputFile()))
    // filter the header row
    .apply("Remove header row",
        Filter.by((String row) -> !((row.startsWith("dwid") || row.startsWith("\"dwid\"")
            || row.startsWith("'dwid'")))))
    // write the rows to database using prepared statement
    .apply("Write to Auths Table in Postgres", JdbcIO.<String>write()
        .withDataSourceConfiguration(JdbcIO.DataSourceConfiguration.create(dataSource(options)))
        .withStatement(INSERT_INTO_MYTABLE)
        .withPreparedStatementSetter(new StatementSetter()));
PipelineResult result = p.run();
try {
  result.getState();
  result.waitUntilFinish();
} catch (UnsupportedOperationException e) {
  // do nothing
} catch (Exception e) {
  e.printStackTrace();
}}

答案 1 :(得分:1)

您分享的旧版Stack Overflow帖子( Skipping header rows - is it possible with Cloud DataFlow? )确实包含您问题的答案。

Apache Beam SDK中的此选项目前不可用,但Apache Beam JIRA问题跟踪器BEAM-123中有开放功能请求。请注意,在编写时,此功能请求仍处于打开状态且尚未解决,并且已经存在2年了。但是,看起来在这个意义上已经做了一些努力,问题的最新更新是从2018年2月开始,所以我建议你保持对JIRA问题的最新更新,因为它最后移到了{{1}组件,它可能会得到更多关注。

考虑到这些信息,我会说您正在使用的方法(在将文件上传到GCS之前删除标题)是您的最佳选择。我不会手动操作,因为您可以轻松编写脚本并自动执行删除标题上传文件过程。

<强> 编辑:

我已经能够使用sdk-java-core提出一个简单的过滤器。它可能不是最优雅的解决方案(我自己不是Apache Beam专家),但它确实有效,您可以根据自己的需要进行调整。它要求您事先知道正在上传的CSV文件的标题(因为它将按元素内容进行过滤),但同样,请将此视为您可以根据需要修改的模板:

DoFn

答案 2 :(得分:-2)

https://medium.com/@baranitharan/the-textio-write-1be1c07fbef0 数据流中的TextIO.Write现在具有withHeader函数,用于向数据添加标题行。此功能已在版本 1.7.0 中添加。

因此,您可以像这样在csv中添加标头:

TextIO.Write.named("WriteToText")
            .to("/path/to/the/file")
            .withHeader("col_name1,col_name2,col_name3,col_name4")
            .withSuffix(".csv"));

withHeader函数自动在标题行的末尾添加换行符。

相关问题