レコード別の値に対するYellowfinの高度な関数の作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223443/513835c2-c812-0cd7-af5b-17d246c43af0.png)


# はじめに
以前の投稿([Yellowfinの高度な関数を作成する](https://qiita.com/celery/items/a1ed1df8d25d04b63ea6))で作成した方法は、幾何平均や共分散などの対象のカラム全体に対して、選択したカラムの全体がどのようになるかというものでしたが、今回はレコードの個々の値に対する関数を作成する方法を紹介していきたいと思います。
開発環境の構築については前回の記事の[はじめに](https://qiita.com/celery/items/a1ed1df8d25d04b63ea6#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)のとおりに、公式wikiの[高度な関数の基礎](https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2294171)通りに進めていくとapplyAnalyticFunctionから必要なメソッドができるようになります。

# 文字列の抜き出し(Substring)の高度な関数
前回の記事ではカラム全体の値に対して処理する必要があったためクラス内でプライベート変数を持っていましたが、今回は必要ありません。
ソースの説明としては、acceptsNativeTypeで対象となるデータ型がテキストであるものを処理し、getReturnTypeのテキスト型で戻り値を返すというようになっています。ここで使う定数はこのページ[高度な関数付録](https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2294166)を参考にしてください。
setupParametersでパラメーターの入力を求めていて、ここに何番目の文字からを対象にするのかという1つ目のパラメーターと何文字を切り出すのかという2つ目のパラメーターの入力をさせます。
メインの処理部分はapplyAnalyticFunctionの中身に当たるのですが、パラメーター名を指定して値を取得するのですが、パラメーターのsetDataTypeをTYPE_NUMERICにすると、取得したときの方がBigDecimalになるため、この値で変数に格納します。このメソッドの1つめのint引数はレコードの何行目か、2つめのObjectはそのカラムの値を持っているため、ここではarg1を文字列化したものにJavaのsubstringを加えています。この引数にパラメーターで取得した値をいい感じに入れてあげると個々の値に対しての処理がされていきます。

```java:Substring.java
import java.math.BigDecimal;
import com.hof.mi.interfaces.AnalyticalFunction;

public class Substring extends AnalyticalFunction{

	@Override
	public boolean acceptsNativeType(int arg0) {
		// TODO 自動生成されたメソッド・スタブ
		return arg0 == TYPE_TEXT;
	}

	@Override
	public Object applyAnalyticFunction(int arg0, Object arg1) throws Exception {
		// TODO 自動生成されたメソッド・スタブ
		//System.out.println(getParameterValue("SUBSTR1").toString());
		BigDecimal inputColumn = (BigDecimal) getParameterValue("SUBSTR1");
		int i = inputColumn.intValue();
		//System.out.println(getParameterValue("SUBSTR2").toString());
		BigDecimal inputColumn2 = (BigDecimal) getParameterValue("SUBSTR2");
		int j = inputColumn2.intValue();
		
		return arg1.toString().substring(i-1,i+j-1);
		//return inputColumn.toString();
	}

	@Override
	public String getCategory() {
		// TODO 自動生成されたメソッド・スタブ
		return "テキスト";
	}

	@Override
	public String getColumnHeading(String arg0) {
		// TODO 自動生成されたメソッド・スタブ
		return "SUBSTR_"+arg0;
	}

	@Override
	public String getDescription() {
		// TODO 自動生成されたメソッド・スタブ
		return "substring_function";
	}

	@Override
	public String getName() {
		// TODO 自動生成されたメソッド・スタブ
		return "SUBSTR_FUNCTION";
	}

	@Override
	public int getReturnType() {
		// TODO 自動生成されたメソッド・スタブ
		return TYPE_TEXT;
	}
	
	protected void setupParameters()
	 {
	   Parameter p = new Parameter();
	   p.setUniqueKey("SUBSTR1");
	   p.setDisplayName("number1");
	   p.setDescription("何番目の文字から切り取るか数字を入力します。");
	   p.setDataType(TYPE_NUMERIC);
	   p.setAcceptsFieldType(TYPE_NUMERIC, true);
	   p.setDisplayType(2);
	   addParameter(p);
	   
	   p = new Parameter();
	   p.setUniqueKey("SUBSTR2");
	   p.setDisplayName("number2");
	   p.setDescription("切り取る長さを数字で入力します。");
	   p.setDataType(TYPE_NUMERIC);
	   p.setAcceptsFieldType(TYPE_NUMERIC, true);
	   p.setDisplayType(2);
	   addParameter(p);

	 }
}
```

# 3つのカラムの文字列の連結(Combine)の高度な関数
次は対象のカラムの前に選択したカラム2つの文字列をつなげる処理を解説していきます。
acceptsNativeTypeとgetReturnTypeは同じくTYPE_TEXTです。数値のカラムを対象にする場合はTYPE_NUMERICを指定するイメージです。ここも[高度な関数付録](https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2294166)を参考にしてください。
先の関数との違いは、選択させるパラメーターに他のカラムを対象にすることです。そのため、パラメーターのsetDataTypeとsetDisplayTypeをDISPLAY_SELECTにしています。
メインの処理自体は簡単で、パラメーターで取得する選択したカラムの値をObject型で取得し、arg0の引数でそのレコードのカラムを確定します。これを変数に入れてあとはつなげるだけです。



```java:Combine.java
import com.hof.mi.interfaces.AnalyticalFunction;

public class Combine extends AnalyticalFunction{

	@Override
	public boolean acceptsNativeType(int arg0) {
		// TODO 自動生成されたメソッド・スタブ
		return arg0 == TYPE_TEXT;
	}
	
	@Override
	public Object applyAnalyticFunction(int arg0, Object arg1) throws Exception {
		// TODO 自動生成されたメソッド・スタブ
		Object[] inputColumn = (Object[])getParameterValue("COLUMN1");
		String s = inputColumn[arg0].toString();
		Object[] inputColumn2 = (Object[])getParameterValue("COLUMN2");
		String t = inputColumn2[arg0].toString();
		StringBuilder buf = new StringBuilder();
		buf.append(s);
		buf.append(t);
		buf.append(arg1.toString());

		return buf.toString();

	}

	@Override
	public String getCategory() {
		// TODO 自動生成されたメソッド・スタブ
		return "テキスト";
	}

	@Override
	public String getColumnHeading(String arg0) {
		// TODO 自動生成されたメソッド・スタブ
		return "COMBINE_"+arg0;
	}

	@Override
	public String getDescription() {
		// TODO 自動生成されたメソッド・スタブ
		return "combine_function";
	}

	@Override
	public String getName() {
		// TODO 自動生成されたメソッド・スタブ
		return "COMBINE_FUNCTION";
	}

	@Override
	public int getReturnType() {
		// TODO 自動生成されたメソッド・スタブ
		return TYPE_TEXT;
	}
	
	protected void setupParameters()
	 {
	   Parameter p = new Parameter();
	   p.setUniqueKey("COLUMN1");
	   p.setDisplayName("column1");
	   p.setDescription("初めの文字列のカラムを選択してください。");
	   p.setDataType(TYPE_FIELD);
	   p.setAcceptsFieldType(TYPE_TEXT, true);
	   p.setDisplayType(DISPLAY_SELECT);
	   addParameter(p);
	   
	   p = new Parameter();
	   p.setUniqueKey("COLUMN2");
	   p.setDisplayName("column2");
	   p.setDescription("2番目に続ける文字列のカラムを選択してください。");
	   p.setDataType(TYPE_FIELD);
	   p.setAcceptsFieldType(TYPE_TEXT, true);
	   p.setDisplayType(DISPLAY_SELECT);
	   addParameter(p);

	 }
}

```

# おわりに
今回は前回とは違って割と普通の関数としての使い方である高度な関数の作り方を紹介しました。前回の記事ではカラム全体に対しての処理だったので分かりづらい計算式も使いましたが、今回の記事ではかゆいところに手が届くような関数を作るきっかけになるのではないかと思います。個人的には小数点の切り上げの関数やゼロパディングする関数を作成しましたが、ちょこっと便利な関数を作るのには参考になるのでと思います。