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