Snowflakeの外に置いたコードを、SQLからそのまま関数として呼び出せるのがExternal Functionです。SnowflakeはAWS上で動くため、Amazon API GatewayをプロキシにAWS Lambdaを呼ぶ構成が定番になります。本記事では、API Integrationの作り方とIAM信頼関係、JSONバッチのフォーマット、同期/非同期と3つのタイムアウト、そしてAmazon BedrockによるAI推論連携まで、私たちが検証段階で先に踏み抜いた落とし穴を交えて実務目線で整理します。

01External Function とは何か

External Function は、Snowflake の外部で実行されるコードを呼び出すユーザー定義関数です。関数の実体は AWS Lambda などのリモートサービス側にあり、Snowflake には「どこを、どう呼ぶか」という設定だけがデータベースオブジェクトとして残ります。SQL の中で SELECT my_ext_func(col) のように書くだけで、外部の処理結果が列として返ってくるのが最大の魅力です。用途としては、社内APIやSaaSのデータ取得、住所正規化や名寄せ、トークナイゼーション、そして近年増えているLLMによる推論といった、Snowflakeネイティブでは書きにくい処理を外へ委譲するケースが中心になります。

ただし万能ではありません。現時点でサポートされるのはスカラー関数のみで、表関数(テーブル値関数)としては定義できません。DEFAULT句やCOPYの変換式では使えず、Secure Data Sharing で共有するオブジェクトにも含められません。内部UDFに比べてネットワークを1往復挟むぶんレイテンシとオーバーヘッドが大きい点も、設計時に必ず意識しておくべき前提です。

02全体構成とデータの流れ

External Function の構成は、大きく3つのレイヤーで理解すると迷いません。Snowflake 側の「External Function + API Integration」、AWS 側の「プロキシサービス(Amazon API Gateway)」、そして実処理を行う「リモートサービス(AWS Lambda)」です。Snowflake は直接 Lambda を叩くわけではなく、必ず API Gateway を経由します。API Gateway が認証・スロットリング・ロギングの窓口となり、その先の Lambda が引数を受け取って処理し、結果を JSON で返します。Lambda はさらに外部API や Amazon Bedrock を呼びに行くこともできます。

External Function の呼び出しフローSigV4署名AWS_IAM認可呼び出しSnowflakeExternal Function+ API IntegrationAmazonAPI GatewayAWS Lambdaリモートサービス外部API /Amazon BedrockJSONレスポンス(1バッチ最大10MB・行番号を保持して返す)
Snowflakeは必ずAPI Gatewayを経由してLambdaを呼ぶ。行の集合はJSONバッチにまとめて送られ、結果は同じ行番号を保持して戻る。

03API Integration と IAM 信頼関係

接続の要になるのが API Integration です。これは「どの AWS ロールで、どの URL プレフィックスへの呼び出しを許可するか」を定義する Snowflake 側のオブジェクトで、作成には ACCOUNTADMIN もしくは CREATE INTEGRATION 権限が必要です。基本形は api_provider = aws_api_gateway、実際に assume する IAM ロールの ARN を指す api_aws_role_arn、そして呼び出しを許すエンドポイントを絞る api_allowed_prefixes の3点セットです。プライベート接続の場合は api_provider = aws_private_api_gateway を使います。

認証は IAM ベースです。Snowflake は指定した IAM ロールを assume し、SigV4 署名付きで API Gateway を呼びます。ここで肝になるのが信頼関係の設定です。API Integration を作成した後に DESCRIBE INTEGRATION を実行すると、API_AWS_IAM_USER_ARN(Snowflake 側のプリンシパル)と API_AWS_EXTERNAL_ID(外部ID)が得られます。この2値を AWS 側 IAM ロールの信頼ポリシーに書き戻し、sts:ExternalId の条件として external_id を突き合わせることで、初めて assume が成立します。ロール側には API Gateway を呼ぶための execute-api:Invoke 権限も付与しておきます。

現場のコツ:私たちの検証環境で、API_AWS_EXTERNAL_ID の末尾に付く「=」をコピー時に取りこぼし、assume が延々と失敗するケースを先に踏みました。外部IDはBase64的な文字列で末尾が「=」になることがあるため、必ず全体を正確に貼り付けます。この経験を踏まえ、本番構築ではDESCRIBE結果をそのままIaC変数へ流し込み、手作業のコピペを排除しています。

04JSON バッチのフォーマットと MAX_BATCH_ROWS

External Function は行を1件ずつ呼ぶわけではありません。Snowflake は複数行をまとめて JSON バッチにし、1リクエストとして送ります。リクエストボディは data というキーを持つ辞書で、その値が行の配列です。各行もまた配列で、先頭要素が0始まりの行番号、以降が関数の引数になります。Lambda 側は同じ形で、行番号と処理結果のペアを data 配列に詰めて返します。Lambda プロキシ統合なら {"statusCode": 200, "body": ...} の形にラップします。重要なのは、入力と出力で行数と行番号を必ず一致させることです。

リクエスト / レスポンスの JSON バッチリクエスト(Snowflake → Lambda){"data": [[0, "en", "Hello"],[1, "en", "World"]]}先頭 = 行番号 / 以降 = 引数レスポンス(Lambda → Snowflake){"data": [[0, "こんにちは"],[1, "世界"]]}行番号と行数を入力に一致させるバッチの境界・行の順序は保証されないため、行ごとに独立して処理する。
行番号(0始まり)が入力と出力を対応づける。順序やバッチ分割はSnowflakeに委ねられるため、状態を持たず行単位で完結させる設計が前提。

1バッチに詰める行数は MAX_BATCH_ROWS で上限を指定できます。バッチが大きいほど1呼び出しあたりのスループットは上がりますが、その分だけ処理時間とレスポンスサイズが膨らみます。レスポンスは1バッチあたり最大10MBという制約があるため、大きな値を返す関数ほど小さめのバッチが安全です。バッチの分割方法や行順序は Snowflake 側の裁量で、保証されない点にも注意が必要です。

05同期・非同期と3つのタイムアウト

リモートサービスには同期型と非同期型があります。同期型は POST を受けて処理し、そのレスポンスで結果を返すシンプルな方式です。一方の非同期型は、POST に対してまず即座に受領応答(HTTP 202)を返し、Snowflake が HTTP GET でポーリングしながら完了を待ちます。処理に時間がかかる関数では非同期型が有効で、これによって API Gateway や Lambda 側のタイムアウトに引っかかりにくくなります。ただし非同期でも Snowflake 側の待機上限は10分で、これは変更できません。

ここで整理しておきたいのが「3つのタイムアウト」です。ひとつめは API Gateway の統合タイムアウト。従来は最大29秒でしたが、2026年現在は 2024年6月のアップデートにより、リージョン REST API とプライベート REST API では Service Quotas から29秒超へ引き上げられるようになりました(アカウントのスロットリング上限の引き下げを伴う場合があります)。ふたつめは Lambda の最大実行時間で、上限は15分です。みっつめが前述の Snowflake 非同期待機の10分です。これらの階層をまたいで整合させることが、安定運用の鍵になります。

現場のコツ:PoC段階で、処理の重い外部API連携を同期型・大きめバッチで組んだところ、API Gatewayの29秒統合タイムアウトを想定外に踏み抜くことを先に確認できました。これを本番へ持ち込まないよう、本番構成では「非同期型に切り替える」「MAX_BATCH_ROWSを下げて1呼び出しを軽くする」の二段構えで設計し、タイムアウト起因の失敗を未然に防いでいます。検証で先に踏むからこそ、本番は静かに回ります。

06リトライと冪等性の設計

External Function は信頼性のために自動リトライを行います。一時的なネットワークエラー、HTTP 429(スロットリング)、HTTP 5XX を受け取ると、Snowflake はリクエストを再送します。便利な反面、これは「同じ行が複数回処理されうる」ことを意味します。DBへの書き込みや課金APIの呼び出しなど副作用のある処理をリモートサービス側で行うと、リトライによって二重実行が起きかねません。

対策の基本は、関数をステートレスかつ冪等に保つことです。Snowflake は各バッチに sf-external-function-query-batch-id ヘッダを付与するので、Lambda 側でこのIDを見て「すでに処理済みのバッチか」を判定すれば、重複を排除できます。ベストプラクティスとしても、戻り値は各入力行のみに依存させ、バッチ全体の文脈や外部状態に依存させないことが推奨されています。

現場のコツ:テスト段階で、あえて5XXを注入してリトライを誘発し、副作用を持つ関数が二重に走らないかを検証しました。ここで二重処理の芽を見つけられたため、本番ではbatch-idをキーにした冪等化を最初から組み込み、リトライが起きても結果が一意に定まる設計にしています。「リトライは起きる前提」で組むのが外部連携の鉄則です。

07用途 — 外部API連携とBedrockによるAI推論

External Function の典型的な使いどころは2つに大別できます。ひとつは外部API・SaaSとのデータ連携で、住所正規化、企業情報の突合、翻訳、ジオコーディングなどをSQLの中に自然に織り込めます。もうひとつが近年伸びているAI推論で、Lambda から Amazon Bedrock を呼び、Claude などのモデルにテキスト分類・要約・抽出をさせて結果を列として返すパターンです。生成AI用途は1リクエストの処理が長くなりがちなため、前述のAPI Gatewayタイムアウト引き上げ(29秒超)や非同期型との相性が良い領域でもあります。

SnowflakeがAWS上で動く強みは、周辺サービスとの統合のしやすさに表れます。ネットワークを外に出したくない場合は aws_private_api_gateway と AWS PrivateLink でプライベート接続にでき、通信をインターネットから隔離できます。Lambda の環境変数やレスポンスに含まれる機微情報は KMS で暗号化し、Secrets Manager と組み合わせて外部APIキーを安全に扱えます。IAM でロールの権限を最小化し、API Gateway のリソースポリシーで呼び出し元をさらに絞れば、多層で守れます。

08External Function の立ち位置と代替、まとめ

最後に、選択肢の広がりにも触れておきます。Snowflake には近年、UDFやストアドプロシージャから直接外部ネットワークへ出る External Access Integration や、AI推論をSnowflake内で完結させる Snowflake Cortex といった機能が加わりました。単純なアウトバウンドHTTPS呼び出しやLLM推論だけなら、これらの方が構成がシンプルになる場面もあります。とはいえ External Function は、API Gateway を挟んだIAMベースの堅牢な認証、AWS側でのスロットリング・ロギング・WAFといった運用制御、そして既存のLambda/API資産の活用という点で、依然として強力な選択肢です。要件に応じて使い分けるのが正解です。

まとめると、External Function 連携の勘所は「API IntegrationとIAM信頼関係を正確に結ぶ」「JSONバッチの行番号契約を守る」「3つのタイムアウトを階層で整合させる」「リトライ前提で冪等に組む」の4点に集約されます。私たちは低コストの小規模導入から最大規模まで、複数業種でAWS×Snowflakeの設計・構築・運用を手がけてきましたが、その中で得た最大の学びは、コストや障害の芽は必ず検証段階で先に踏み抜いておく、という姿勢そのものでした。本番を静かに回し続けるための土台は、地味な検証の積み重ねにあります。

参考情報(一次情報)

EMWはAWS×Snowflakeの設計・構築・運用を一気通貫で支援しています。External FunctionやBedrock連携の構成でお悩みなら、まずはお気軽にご相談ください。

相談する
← ブログ一覧へ戻る