めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

Jaql入門(3) - ユーザ定義関数

median

関数を定義して使用する例です。足し算(add)と配列をソートしたときの真ん中の値(median)を定義して使用しています。

$ nl function.jql
     1  $add = fn($a, $b) (
     2    $a + $b
     3  );

     4  // $add( 1, 1 ); => 2

     5  $median = fn($items) (
     6    $sorted = $items -> sort by [$],
     7    $sorted[count($sorted)/2]
     8  );

     9  // $median( [ 1, 4, 5, 3, 2 ] ); => 3

    10  $exam = read(hdfs("exam"));
    11  $results = $exam -> transform $add($.math, $.science);

    12  $results; // [ 110, 120, 100, 100, 120, 150, 80 ]
    13  $median( $results ); // 110

    14  quit;

$ jaqlshell -cb function.jql
[
  110,
  120,
  100,
  100,
  120,
  150,
  80
]
110

MySplit

Java で記述したクラスをユーザ定義関数として使用することもできます。内部では、JSON データを扱うための Json* クラスを利用します。Writable や WritableComparable を気にする必要はありません。

$ nl udf/MySplit.java
     1  package udf;
     2
     3  import com.ibm.jaql.json.type.JsonString;
     4  import com.ibm.jaql.json.type.MutableJsonString;
     5  import com.ibm.jaql.json.util.JsonIterator;
     6
     7  public class MySplit {
     8    public JsonIterator eval(JsonString jstr, JsonString jdelim)
     9                        throws Exception {
    10      if (jstr == null || jdelim == null) {
    11        return null;
    12      }
    13      String str = jstr.toString();
    14      String delim = jdelim.toString();
    15
    16      final String[] splits = str.split(delim);
    17
    18      final MutableJsonString resultStr = new MutableJsonString();
    19      return new JsonIterator(resultStr) {
    20        int i = 0;
    21
    22        public boolean moveNext() {
    23          if (i >= splits.length) {
    24            return false;
    25          }
    26          resultStr.setCopy(splits[i]);
    27          i++;
    28          return true; // currentValue == resultStr
    29        }
    30      };
    31    }
    32  }

$ javac udf/MySplit.java
$ jar cf udf.jar udf

文字列と区切り記号を受け取って、分割した文字列の配列を返します。実際には、配列の要素を Iteration で返す、JsonIterator インスタンスを返します。

$ nl mysplit.jql
     1  registerFunction("mysplit", "udf.MySplit");
     2  $path = '/var/log/messages';

     3  mysplit($path, "/");
     4  count(mysplit($path, "/"));
     5  quit;

$ jaqlshell -cb -j udf.jar mysplit.jql
[
  "",
  "var",
  "log",
  "messages"
]
4

jaqlshell の -j オプションで UDF を含む jar を指定します。Jaql のコード内では、事前に registerFunction() で UDF としてクラスを登録します。