Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Pentaho数据集成中填补流中的数据空白,是否可能?_Pentaho_Kettle - Fatal编程技术网

在Pentaho数据集成中填补流中的数据空白,是否可能?

在Pentaho数据集成中填补流中的数据空白,是否可能?,pentaho,kettle,Pentaho,Kettle,我有一个CSV文件与货币交换欧元美元。该文件是从中下载的。我从2013年10月10日起下载了CSV,其中包含数据 然而,数据中存在差距,即没有转换率的天数 我一直在努力寻找一种简单(但通用)的方法来填补空白,比如说,最后一个非空值。我能做到这一点的唯一方法是链接4个“Get previous row fields”并在计算器中使用NVL获取第一个非空值。但只有当一条流中的间距不大于4行时,这种方法才有效 该图像表示转换: 我的第一个问题归结为:在有间隙的流中,是否有一种进行插值/外推的通用方法

我有一个CSV文件与货币交换欧元美元。该文件是从中下载的。我从2013年10月10日起下载了CSV,其中包含数据

然而,数据中存在差距,即没有转换率的天数

我一直在努力寻找一种简单(但通用)的方法来填补空白,比如说,最后一个非空值。我能做到这一点的唯一方法是链接4个“Get previous row fields”并在计算器中使用NVL获取第一个非空值。但只有当一条流中的间距不大于4行时,这种方法才有效

该图像表示转换:

我的第一个问题归结为:在有间隙的流中,是否有一种进行插值/外推的通用方法

我试图使用“修改后的JavaScript值”,但API仍然无法使用。此外,这一步似乎只有MapReduce组合的Map部分,我可能需要两者


所以,我的第二个问题是:有没有一种方法可以用非Java语言(Scala、Clojure、Jython或JS)编写MapReduce组合体?

尽管这并不是您想要的,但您可以通过使用具有通用功能的用户定义Java类组件来实现您的目标。将步骤
Get previous row字段
行中的非值
替换为此组件的单个实例。在此组件的“类-处理器”部分插入以下代码:

Object[] previousRow;

public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
    // First, get a row from the default input hop
    Object[] r = getRow();

    // If the row object is null, we are done processing.
    if (r == null) {
      setOutputDone();
      return false;
    }

    // It is always safest to call createOutputRow() to ensure that your output row's Object[] is large
    // enough to handle any new fields you are creating in this step.
    Object[] outputRow = createOutputRow(r, data.outputRowMeta.size());

    // copy all input fields to the output fields

    for (int i=0; i < getInputRowMeta().size(); i++) {
        logBasic(data.inputRowMeta.getString(r, i));
        if (data.inputRowMeta.getString(r, i) == null && (previousRow != null))  {
            // if the current field is empty take it from the previous row
            outputRow[i] = previousRow[i];
        }   
        else {
            // otherwise use the current row
            outputRow[i] = r[i];
        }

    }

    putRow(data.outputRowMeta, outputRow);
    // store the current row as future previous row
    previousRow = data.outputRowMeta.cloneRow(outputRow);

    return true;
}
用户定义的Java类组件的配置如下:

输出文本文件包含“无间隙”的增强行:

注:

  • 该组件是针对这四种数据类型进行测试的,但原则上它应该适用于所有数据类型
  • 它与字段的实际数量无关
  • 一旦一个字段被填充,它就永远不可能是“未填充的”,这对您的设置很好(我猜),但这可能不适用于其他设置
  • 该机制仅在字段为
    null
    时有效。仅包含空格的字符串可能会将其打断,因此请确保在将所有字符串插入组件之前修剪它们
该代码是作为教程使用编写的

附录

@manu提供的链接包含以下代码。它包含数字格式的特定处理。请注意,它不再是完全通用的

Object[] previousRow;
RowMetaInterface outputMeta;

public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
    // First, get a row from the default input hop
    Object[] r = getRow();

    // If the row object is null, we are done processing.
    if (r == null) {
        setOutputDone();
        return false;
    }

    if (outputMeta == null) {
        outputMeta = data.outputRowMeta.clone();
    for(int i=0; i < outputMeta.size(); i++) {
        ValueMetaInterface meta = outputMeta.getValueMeta(i);
        if (meta.getType() == ValueMetaInterface.TYPE_NUMBER) {
            meta.setPrecision(4);
            meta.setConversionMask("#.####");
        }
    }
}

// It is always safest to call createOutputRow() to ensure that your output row's Object[] is large
// enough to handle any new fields you are creating in this step.
Object[] outputRow = createOutputRow(r, data.outputRowMeta.size());

// copy all input fields to the output fields

for (int i=0; i < getInputRowMeta().size(); i++) {
    if ((r[i] == null) && (previousRow != null)) {
        // if the current field is empty take it from the previous row
        outputRow[i] = previousRow[i];
    }
    else {
        // otherwise use the current row
        outputRow[i] = r[i];
    }     
}

putRow(outputMeta, outputRow);
// store the current row as future previous row
previousRow = outputMeta.cloneRow(outputRow);

return true;
}
对象[]上一行;
RowMeta接口outputMeta;
公共布尔processRow(StepMetaInterface smi、StepDataInterface sdi)引发异常
{
//首先,从默认输入跃点获取一行
对象[]r=getRow();
//如果row对象为null,则完成处理。
if(r==null){
setOutputDone();
返回false;
}
if(outputMeta==null){
outputMeta=data.outputRowMeta.clone();
对于(int i=0;i
您可以结合使用以下三个步骤:

1) 分析查询-允许您在当前行之前或之后获取N行字段的值;在您的情况下,您需要提前获取日期1行(下一个可用日期)

2) 计算器-确定行的上一个日期后,使用它计算日期之间的天数

3) 将_克隆的字段数_计算为dbd-1(缺少的天数

4) 在“克隆行”步骤中使用该字段可以根据需要多次复制行;添加克隆号字段

5) 将克隆号添加为日期的天数,即可获得它所指的日期

此外,分析查询步骤允许您将一个字段指定为“分组依据”字段,这样,如果您有美元的x利率,然后有英镑的x利率,那么最后的美元x利率日将检索空值作为下一个值

下面是一个示例KTR文件:

“数据网格”步骤会生成几行,其中包含一些数据间隙:

分析查询获取相同货币值的下一个日期

然后,计算器步骤计算缺少多少行。请注意,每种货币的最后一天将有
null
作为值,因此我们需要调整该值并使用0(如果A为null,则NVL(A,B)返回B,否则返回A)

克隆行:获取一行并创建副本。

clone_number字段允许我们计算行引用的实际日期

最后,这里是数据。您需要的字段是新的日期、货币和汇率。使用“选择值”对字段列表重新排序,并删除不再需要的字段。


如您所见,现在我们有了2014-01-03和2014-01-04的数据,使用了之前的已知值。

嗨,马库斯,谢谢您的提示。这是Java,但我会搞定的。所提供的脚本无法正常工作,因为对于非字符串字段(如我的货币汇率数据),data.inputRowMeta.getString(r,i)将始终为空。我已经试过了
NUMBER;STRING;DATE;CURRENCY
1;A;01.02.2014; 012,50
2;B;01.02.2014; 013,50
2;B;03.12.2001; 013,50
4;B;03.12.2001; 013,50
5;C;03.12.2001; 013,50
6;C;20.03.2005; 018,20
7;D;20.03.2005; 018,20
Object[] previousRow;
RowMetaInterface outputMeta;

public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
    // First, get a row from the default input hop
    Object[] r = getRow();

    // If the row object is null, we are done processing.
    if (r == null) {
        setOutputDone();
        return false;
    }

    if (outputMeta == null) {
        outputMeta = data.outputRowMeta.clone();
    for(int i=0; i < outputMeta.size(); i++) {
        ValueMetaInterface meta = outputMeta.getValueMeta(i);
        if (meta.getType() == ValueMetaInterface.TYPE_NUMBER) {
            meta.setPrecision(4);
            meta.setConversionMask("#.####");
        }
    }
}

// It is always safest to call createOutputRow() to ensure that your output row's Object[] is large
// enough to handle any new fields you are creating in this step.
Object[] outputRow = createOutputRow(r, data.outputRowMeta.size());

// copy all input fields to the output fields

for (int i=0; i < getInputRowMeta().size(); i++) {
    if ((r[i] == null) && (previousRow != null)) {
        // if the current field is empty take it from the previous row
        outputRow[i] = previousRow[i];
    }
    else {
        // otherwise use the current row
        outputRow[i] = r[i];
    }     
}

putRow(outputMeta, outputRow);
// store the current row as future previous row
previousRow = outputMeta.cloneRow(outputRow);

return true;
}