【问题标题】:Talend - Transposing Input File with Dynamic Number of ColumnsTalend - 使用动态列数转置输入文件
【发布时间】:2014-08-14 15:17:11
【问题描述】:

我遇到了一个非常棘手的情况,还没有使用 Talend 想出我自己的解决方案。我有一个具有动态列数的输入 csv 文件,需要转置此文件以创建所需的输出文件。输入文件如下所示:

ID1 | Units1 | Count | Val1a | Val2a | Val3a | Val1b | Val2b | Val3b | Val1c | Val2c | Val3c
ID2 | Units2 | Count | Val1d | Val2d | Val3d | Val1e | Val2e | Val3e

如您所见,每排 Val 都是三胞胎,我需要三胞胎保持在一起。 Count 列包含在该行上找到的三元组的数量,因为每一行都是动态的。我需要的最终输出是:

ID1 | Units1 | Val1a | Val2a | Val3a
ID1 | Units1 | Val1b | Val2b | Val3b
ID1 | Units1 | Val1c | Val2c | Val3c
ID2 | Units2 | Val1d | Val2d | Val3d 
ID2 | Units2 | Val1e | Val2e | Val3e

我尝试过旋转和取消旋转这些行,但这不允许我将三元组保持在一起。我是否可以通过 Java 脚本发送输入文件,并在其中解析文件并以这种格式输出到 csv 文件?

非常感谢任何帮助。

【问题讨论】:

  • 您想使用一个 tJavaFlex 组件,该组件允许您为每个输入行创建一个或多个行输出。

标签: csv talend unpivot dynamic-columns data-mapping


【解决方案1】:

您应该能够在 tJavaRow 中编写一段自定义的 Java 代码,以便根据需要解析出这些值。

您可能希望使用 tFileInputRaw 将原始源作为原始输入读取,这样您就可以在 tJavaRow 组件中解析整个内容。您需要向 tJavaRow 添加一个输出架构,其中包含您的 id、unit、value1、value2 和 value3 的列。

因为您有需要分解为多行的行,您最好将 1a、1b、1c 和 1d 等值连接在一起,然后您可以使用 tNormalize 组件进一步分解为单独的行将根据需要分解该行。

在我看来,tJavaRow 组件中的代码可能类似于:

// First we split the data on the delimiter of the file, assuming comma separated for now
String[] splitData = inputrow.content.split(",");
// Initialise the three value strings
String value1 = ""
String value2 = ""
String value3 = ""
for (int i = 0; i < splitData.length; i++) {
    if (i == 1) {
        // id field is the first field
        String id = splitData[i];
    } else if (i == 2) {
        unit field is the second field
        String unit = splitData[i];
    } else if (i == 3) {
        // Don't need to do anything with the count data
    } else if (i % 3 == 1) {
        // value1 fields are 4, 7, 10 etc so modulo 3 == 1
        if (value1.length == 0) {
            value1 + splitData[i];
        } else {
            // if the value field isn't empty (ie. for val1b) then we need to add a delimiter for further processing
            value1 + "|" + splitData[i];
        }
    } else if (i % 3 == 1) {
        if (value2.length == 0) {
            value2 + splitData[i];
        } else {
            value2 + "|" + splitData[i];
        }
    } else if (i % 3 == 3) {
        if (value3.length == 0) {
            value3 + splitData[i];
        } else {
            value3 + "|" + splitData[i];
        }
    }
}

// Finally we then assign these strings to their output schema columns
output_row.id = id;
output_row.unit = unit;
output_row.value1 = value1;
output_row.value2 = value2;
output_row.value3 = value3;

如果您的任何字段的内容可以包含逗号(或您的文件具有的任何分隔符,您将遇到一些问题,因为您需要创建一个更复杂的解析方法来允许引用的字段数据。

从这里您只需要连接 tNormalize 组件并将其拆分到 |字符(或者您选择的任何字符,它应该是不会在源数据中找到的字符)。您可能需要执行此操作 3 次才能获得所需的输出(因为您需要对三列进行规范化)。

【讨论】:

  • 使用 tJavaFlex 你不需要 tNormalize :)
  • 没错,但您实际上正在执行 tNormalize 在您自己手写的 Java 代码中会执行的操作。作为一名 Java 开发人员,我宁愿尽可能多地使用组件,并且只求助于编写组件对我没有帮助的 Java(例如这个客户解析器)。
  • @BalazsGunics 我能够让它工作。不过我很好奇,如何使用 tJavaFlex 代替 tNormalize?
  • tJavaFlex component guide 应该对你有帮助。我没有太多地使用它,但是您基本上想将要在 tJavaRow 中执行的代码包装在一个循环所有数据行的 for 循环中。根据您编写(和维护)Java 代码的舒适程度,这可能是一个更好的选择。
  • 我最终创建了这两种解决方案。使用 tJavaFlex 的 @BalazsGunics 解决方案比使用 tJavaRow + tNormalize 更高效、更快。感谢您提供这两种解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多