Pentaho(Spoon)でのユーザ定義Javaクラス・ステップの使い方

Pentaho(Spoon)では、ステップのひとつにJavaを使用することができます。

これは、「ユーザ定義Javaクラス」と呼ばれ、厳密にはPureJavaでなく、JaninoというJavaクラスを生成するコンパイラによって動的に生成されます。

とはいえ、Javaには変わりないため、豊富なライブラリを利用することも出来ますし、JavaScriptで記述した場合に比べて高速です。(一般的には3倍くらい早いと言われているようですね。)

「ユーザ定義Javaクラス」をデータ変換のステップに加えて、開いてみると、上記のような画面になります。

左側に「フィールドを取得中 しばらくお待ちください」といったメッセージが表示されますが、いつまでたっても、解消はしません。

なぜなら、下記のエラーが出ているからです。

ERROR (version 8.0.0.0-28, build 8.0.0.0-28 from 2017-11-05 07.27.50 by buildguy) : 前のステップからフィールド取得でエラーが発生しました
ERROR (version 8.0.0.0-28, build 8.0.0.0-28 from 2017-11-05 07.27.50 by buildguy) : org.pentaho.di.core.exception.KettleStepException: 
Error initializing UserDefinedJavaClass to get fields: 
Line 3, Column 1: Non-abstract class "Processor" must implement method "boolean org.pentaho.di.trans.steps.userdefinedjavaclass.TransformClassBase.
processRow(org.pentaho.di.trans.step.StepMetaInterface, org.pentaho.di.trans.step.StepDataInterface) 
throws org.pentaho.di.core.exception.KettleException"

at org.pentaho.di.trans.steps.userdefinedjavaclass.UserDefinedJavaClassMeta.getFields(UserDefinedJavaClassMeta.java:398)
at org.pentaho.di.trans.TransMeta.getThisStepFields(TransMeta.java:2005)
at org.pentaho.di.trans.TransMeta.getThisStepFields(TransMeta.java:1955)
at org.pentaho.di.ui.trans.steps.userdefinedjavaclass.UserDefinedJavaClassDialog$9.run(UserDefinedJavaClassDialog.java:531)
at java.lang.Thread.run(Thread.java:745)

「ユーザ定義Javaクラス」では、ステップ内で実行できるクラスとしてコンパイルするため、processRowというメソッドを実装しないと値取得でエラーになります。

そのため、下記のようなソースを記述すればエラーは出なくなりますし、データの加工をユーザ定義Javaクラス内で行うことが可能となります。

String firstnameField;
String lastnameField;
String nameField;
  
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
    // Let's look up parameters only once for performance reason.
    //
    if (first) {
      firstnameField = getParameter("FIRSTNAME_FIELD");
      lastnameField = getParameter("LASTNAME_FIELD");
      nameField = getParameter("NAME_FIELD");
      first=false;
    }
  
    // 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());
  
    String firstname = get(Fields.In, firstnameField).getString(r);
    String lastname = get(Fields.In, lastnameField).getString(r);
  
    // Set the value in the output field
    //
    String name = firstname+" "+lastname;
    get(Fields.Out, nameField).setValue(outputRow, name);
  
    // putRow will send the row on to the default output hop.
    //
    putRow(data.outputRowMeta, outputRow);
  
    return true;
}

少し解説すると、「getParameter(“FIRSTNAME_FIELD”)」などで、前ステップや後続ステップのパラメータ名称を取得できます。

「FIRSTNAME_FIELD」はタグ名なので、下記のように、ステップ下の「パラメータ」で、渡されるパラメータにタグ名をつけて定義しておきましょう。

ちなみに、下記の3つめの定義「NAME_FIELD」<->「newName」は、値を追加しており、アウトプットに項目を追加で定義しています。

(後続のステップで、newNameという項目を使用することができる。)

そして、ソースのもう少し後ろの部分のように「get(Fields.In, firstnameField).getString(r)」で実際の値を取得できます。

さらに、「get(Fields.Out, nameField).setValue(outputRow, name)」で値をセットすれば、アウトプット項目に値をセットできるでしょう。

その際には、下記のように「フィールド」の項目で出力用のフィールドと型を定義しておき、前述の「パラメータ」でタグ付けしておきます。

以上で、「ユーザ定義Javaクラス」のステップでinputからのデータの取得、そして加工、outputへのデータのセットができるようになりました。

次回は、「ユーザ定義Javaクラス」内で、jarなどの外部ライブラリをimportして使用する方法を解説します。

サードパーティの様々なライブラリを使えるようになれば、もっと複雑なことを、比較的簡単にPentahoで実現できるのではないかと思います。