AWS Step Functionsで組み込み関数だけを使って整数の乗算を実装してみた(AWS CDK)
こんにちは、CX事業本部 IoT事業部の若槻です。
最近のAWS Step Functionsのアップデートで、数学演算を実施可能な組み込み関数が追加されました。
追加されたのは、ランダムな数値を取得するStates.MathRandom
と、数値の加算をするStates.MathAdd
のみです。よって乗算や除算は未追加なります。
しかし今回、AWS Step Functionsで組み込み関数だけを使って数値(整数のみ)の乗算を実装をAWS CDKでしてみたのでご紹介します。
やってみた
利用した組み込み関数
実装で利用した組み込み関数はStates.ArrayRange
とStates.MathAdd
です。
States.ArrayRange
を使うと、指定した要素数の配列を作成できます。(ただし配列長の最大は1000です。)
//function "array.$": "States.ArrayRange(1, 9, 2)" //output {"array": [1,3,5,7,9] }
States.MathAdd
を使うと2つの数値の和を取得できます。
//function "value1.$": "States.MathAdd(6, 4)" //output {"value1": 10 }
実装
AWS CDK v2(TypeScript)で次のようなCDKスタックを作成します。
import { aws_stepfunctions, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class AwsCdkAppStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); // States.ArrayRangeで乗数の長さの配列を取得 const getArrayPass = new aws_stepfunctions.Pass(this, 'getArrayPass', { parameters: { 'val.$': 'States.ArrayRange(1, $.multiplier, 1)', }, resultPath: '$.getArrayPassOutput', }); // ループ開始 // 被乗数(multiplicand)の加算を乗数(multiplier)回だけループして積(product)を求める const initLoopArgs = new aws_stepfunctions.Pass( this, 'initReplacementLoop', { parameters: { currentIndex: 1, product: aws_stepfunctions.JsonPath.stringAt('$.multiplicand'), }, resultPath: '$.loopArgs', } ); // States.MathAddでcurrentIndexとproductをインクリメントしていく const concatinateString = new aws_stepfunctions.Pass( this, 'concatinateString', { parameters: { 'currentIndex.$': 'States.MathAdd($.loopArgs.currentIndex, 1)', 'product.$': 'States.MathAdd($.loopArgs.product, $.multiplicand)', }, resultPath: '$.loopArgs', } ); // 乗数回のループが完了したらSucceedへ進んで終了、未完了ならループを継続する const isLoopFinishedChoice = new aws_stepfunctions.Choice( this, 'isLoopFinishedChoice' ) .when( aws_stepfunctions.Condition.numberEqualsJsonPath( '$.multiplier', '$.loopArgs.currentIndex' ), // ループ終了 new aws_stepfunctions.Succeed(this, 'succeed') ) .otherwise(concatinateString); // State Machine new aws_stepfunctions.StateMachine(this, 'myStateMachine', { stateMachineName: 'myStateMachine', definition: getArrayPass .next(initLoopArgs) .next(concatinateString) .next(isLoopFinishedChoice), }); } }
上記をCDK Deployしてスタックをデプロイします。これにより次の定義のState Machineが作成されます。
{ "StartAt": "getArrayPass", "States": { "getArrayPass": { "Type": "Pass", "ResultPath": "$.getArrayPassOutput", "Parameters": { "val.$": "States.ArrayRange(1, $.multiplier, 1)" }, "Next": "initReplacementLoop" }, "initReplacementLoop": { "Type": "Pass", "ResultPath": "$.loopArgs", "Parameters": { "currentIndex": 1, "product.$": "$.multiplicand" }, "Next": "concatinateString" }, "concatinateString": { "Type": "Pass", "ResultPath": "$.loopArgs", "Parameters": { "currentIndex.$": "States.MathAdd($.loopArgs.currentIndex, 1)", "product.$": "States.MathAdd($.loopArgs.product, $.multiplicand)" }, "Next": "isLoopFinishedChoice" }, "isLoopFinishedChoice": { "Type": "Choice", "Choices": [ { "Variable": "$.multiplier", "NumericEqualsPath": "$.loopArgs.currentIndex", "Next": "succeed" } ], "Default": "concatinateString" }, "succeed": { "Type": "Succeed" } } }
State Machine Graphは次のようになります。
動作確認
次のデータをInputにしてState Machineを実行します。
{ "multiplicand": 3, "multiplier": 5 }
実行が成功しました。getArrayPass
Stateでmultiplier
の長さの配列が作成できています。
{ "multiplicand": 3, "multiplier": 5, "getArrayPassOutput": { "val": [ 1, 2, 3, 4, 5 ] } }
suceed
Stateで3 * 5
の乗数の積である15
が取得できました!
{ "multiplicand": 3, "multiplier": 5, "getArrayPassOutput": { "val": [ 1, 2, 3, 4, 5 ] }, "loopArgs": { "product": 15, "currentIndex": 5 } }
注意点
States.ArrayRange
を使っている性質上、multiplierに指定できるのは整数のみとなります。- 冒頭でも書きましたが
States.ArrayRange
で作成できる配列長の最大は1000です。よって乗算のmultiplierは1000以下とする必要があります。
おわりに
AWS Step Functionsで組み込み関数だけを使って整数の乗算をAWS CDKで実装してみました。
正直、乗算をするためだけに今回のような複雑なWorkflowを頑張って組むくらいなら、Lambda関数をTaskで実行した方が良いと思います。ただ、組み込み関数だけでこんなことも出来るんだぞという可能性を示すことは出来たのではないかと思います。
参考
- [アップデート] AWS Step Functionsの組み込み関数が14個追加されて配列や数値などの操作が簡単になりました | DevelopersIO
- AWS Step Functionsの組み込み関数をフル活用して置換箇所が不特定多数の場合の文字列置換をやってみた(AWS CDK) | DevelopersIO
以上