SAP Predictive Analyticsの予測APIをAWS Lambdaを使って実現

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

以前、弊社ブログにてSAP Predictive Analytics(以下、SAP PA)のインストール手順をご紹介させていただきました。SAP PAは作成したモデルを各種言語でエクスポートすることが可能で、その言語にJavaScriptも含まれます。ということで、今回はエクスポートしたコードをLambdaにデプロイして予測APIを実現したいと思います。

SAP PAのモデルのエクスポート

まずはSAP PAからモデルをエクスポートするため、モデルを作成します。今回はインストール後の動作確認に利用するサンプルのモデルを利用します。モデルの作成手順はSAP Predictive Analytics(旧:SAP InfiniteInsight)のTrial版をインストールしてみたをご参照下さい。今回は前述の手順に沿ってCensus01.csvから分類回帰モデルの作成を終えたところから始めます。

implement-sap-predictive-analytics-api-by-lambda1

[次へ]ボタンをクリックします。

implement-sap-predictive-analytics-api-by-lambda3

[保存/エクスポート]メニューをクリックし、[ソースコードの生成]をクリックします。

implement-sap-predictive-analytics-api-by-lambda5

コード形式を[HTML(JavaScript)]にし、[生成されるファイル]名をCensus.htmlとします。また、[生成されたコードの表示]にチェックをいれます。なお、今回はJavaScriptを選びましたが他にもJavaやC、SQLなど様々な形式でモデルをエクスポート可能です。

implement-sap-predictive-analytics-api-by-lambda6

HTMLとJavaScriptによるコードが生成されます。実際にブラウザ上で開くとそのまま実行可能な状態になっています。

implement-sap-predictive-analytics-api-by-lambda8

[class]のリンクをクリックするとスコアが表示されます。また、Formの各説明変数の値を変更するとスコアが更新されるようになっています。

Lambdaファンクションの作成

ではLambdaファンクションを作成したいと思いますが、まずはCensus.htmlのソースコードについて確認してみましょう。Formの入力項目毎にKxen_RobustRegression_0_KxVar12関数のような説明変数毎のスコアを算出する関数が生成されます。また、画面で入力値を変更した際のハンドラー関数としてcomputeScore0が生成されます。

// これより前のCensus.htmlの内容について省略

function Kxen_RobustRegression_0_KxVar12(iValue) {
	CONVFMT = "%.17g"
	lValue = iValue;
	if( iValue == ""  ) {
		return 0.0084301288852809079;
	}
	if ( lValue > 99.0 ) {
		lValue = 99.0;
	}
	else if ( lValue < 1.0 ) {
		lValue = 1.0;
	}
	if( 0 == doublesegcmp( lValue, 1.0, 1, 1.0, 1) ) { 
		return -0.05353748496185684;
	}
	if( 0 == doublesegcmp( lValue, 1.0, 0, 31.969000399112701, 1) ) { 
		return (0.00061686507563880584 * lValue + -0.054154350035585268);
	}
	if( 0 == doublesegcmp( lValue, 31.969000399112701, 0, 32.0, 1) ) { 
		return (0.27230809947161783 * lValue + -8.7398515308752192);
	}

// Kxen_RobustRegression_0_KxVar12関数の内容を省略
	
	if( 0 == doublesegcmp( lValue, 64.035000001662411, 0, 99.0, 1) ) { 
		return (0.00061686507563880628 * lValue + 0.0039077177107035201);
	}
	if( 0 == doublesegcmp( lValue, 99.0, 0, 99.0, 1) ) { 
		return 0.064977360198945344;
	}
	if( lValue > 99.0 ) { 
		return 0.064977360198945344;
	}
	return 0.0084301288852809079;
}

function computeScore0( form ) {
	var score;
	var lInputs = new Array(7);
	var lAllInputs = new Array(7);

	score = 0.0;

	score += Kxen_RobustRegression_0_KxVar0( document.forms[form].input0_0.value );
	document.forms[form].elements['score0'].value = Kxen_RobustRegression_0_KxVar0( document.forms[form].input0_0.value );
	score += Kxen_RobustRegression_0_KxVar3( document.forms[form].input0_3.value );
	document.forms[form].elements['score3'].value = Kxen_RobustRegression_0_KxVar3( document.forms[form].input0_3.value );
	score += Kxen_RobustRegression_0_KxVar5( document.forms[form].input0_5.value );
	document.forms[form].elements['score5'].value = Kxen_RobustRegression_0_KxVar5( document.forms[form].input0_5.value );
	score += Kxen_RobustRegression_0_KxVar6( document.forms[form].input0_6.value );
	document.forms[form].elements['score6'].value = Kxen_RobustRegression_0_KxVar6( document.forms[form].input0_6.value );
	score += Kxen_RobustRegression_0_KxVar10( document.forms[form].input0_10.value );
	document.forms[form].elements['score10'].value = Kxen_RobustRegression_0_KxVar10( document.forms[form].input0_10.value );
	score += Kxen_RobustRegression_0_KxVar11( document.forms[form].input0_11.value );
	document.forms[form].elements['score11'].value = Kxen_RobustRegression_0_KxVar11( document.forms[form].input0_11.value );
	score += Kxen_RobustRegression_0_KxVar12( document.forms[form].input0_12.value );
	document.forms[form].elements['score12'].value = Kxen_RobustRegression_0_KxVar12( document.forms[form].input0_12.value );
	document.forms[ form ].class_resultArea.value = score;
}

// -->
</script>

<!-- これより後のCensus.htmlの内容について省略 -->

では、実際にLambdaファンクションを作成していきたいと思います。Census.htmlからJavaScriptを一通りコピーします。computeScore0関数の部分だけはLambdaのexports.handlerファンクションの中身に入れます。Census.htmlと同じように直接Formの中身は操作できないため一旦JSONに変換して受け渡します。なお、LambdaファンクションのNameはCensusとしています。

exports.handler = function(event, context) {
    var score = 0.0;
    var result = {};
    
    score += Kxen_RobustRegression_0_KxVar0( event.input0_0 );
    result['score0'] = Kxen_RobustRegression_0_KxVar0( event.input0_0 );
    score += Kxen_RobustRegression_0_KxVar3( event.input0_3 );
    result['score3'] = Kxen_RobustRegression_0_KxVar3( event.input0_3 );
    score += Kxen_RobustRegression_0_KxVar5( event.input0_5 );
    result['score5'] = Kxen_RobustRegression_0_KxVar5( event.input0_5 );
    score += Kxen_RobustRegression_0_KxVar6( event.input0_6 );
    result['score6'] = Kxen_RobustRegression_0_KxVar6( event.input0_6 );
    score += Kxen_RobustRegression_0_KxVar10( event.input0_10 );
    result['score10'] = Kxen_RobustRegression_0_KxVar10( event.input0_10 );
    score += Kxen_RobustRegression_0_KxVar11( event.input0_11 );
    result['score11'] = Kxen_RobustRegression_0_KxVar11( event.input0_11 );
    score += Kxen_RobustRegression_0_KxVar12( event.input0_12 );
    result['score12'] = Kxen_RobustRegression_0_KxVar12( event.input0_12 );
    result['score'] = score;

    context.succeed(result);
};

// 以下、Census.htmlに記述されているJavaScript関数をそのままコピー

Lambdaのファンクションは用意出来たので呼び出すためのHTMLファイルを作成します。元々のCensus.htmlの中身をLambdaファンクションを呼び出すように改造しています。ファイル名はCensus_Lambda.htmlとしました。ソースコードとしては元々あったJavaScriptは全て削除してFormの値をJSONに入れてLambdaファンクションを実行し、レスポンスをFormに書き込むだけにしています。なお、JavaScript SDKからLambdaファンクションの実行に関してはブラウザから直接Lambdaファンクションを実行を参照して下さい。

<html>
<head>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.36.min.js"></script>
<script language="JavaScript" type="text/javascript">
<!--
function computeScore0( form ) {
    AWS.config.update({
        accessKeyId : '{your_access_key_id}',
        secretAccessKey : '{your_secret_access_key}'
    });
    AWS.config.region = 'ap-northeast-1';
    var lambda = new AWS.Lambda();
    var params = {
        FunctionName : 'Census',
        Payload : JSON.stringify({
            input0_0 : document.forms[form].input0_0.value,
            input0_3 : document.forms[form].input0_3.value,
            input0_5 : document.forms[form].input0_5.value,
            input0_6 : document.forms[form].input0_6.value,
            input0_10 : document.forms[form].input0_10.value,
            input0_11 : document.forms[form].input0_11.value,
            input0_12 : document.forms[form].input0_12.value
          })
    };
    
    lambda.invoke(params, function(err, data) {
        if (err) {
          console.log(err, err.stack);
        } else {
          var result = JSON.parse(data.Payload);
          document.forms[form].elements['score0'].value = result.score0;
          document.forms[form].elements['score3'].value = result.score3;
          document.forms[form].elements['score5'].value = result.score5;
          document.forms[form].elements['score6'].value = result.score6;
          document.forms[form].elements['score10'].value = result.score10;
          document.forms[form].elements['score11'].value = result.score11;
          document.forms[form].elements['score12'].value = result.score12;
          document.forms[ form ].class_resultArea.value = result.score;
        }
    });
}

// -->
</script>
</head>

<!-- 以下、Census.htmlに記述されている内容そのまま -->

まとめ

Lambdaを利用することでSAP PAの予測APIを簡単に実現することが出来ました。SAP PAはJavaのコードでもエクスポートできるのでそちらについてもいずれ試せればと思います。