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 としてクラスを登録します。