外部ネットワークアクセスの例¶
このトピックでは、ユーザー定義関数とプロシージャから外部ネットワークロケーションにアクセスする例を示します。
Google翻訳 API へのアクセス¶
以下のステップでは、Google翻訳 API にアクセスするための外部アクセス統合を作成するコードを示します。ステップでは、セキュリティの統合と、ステートメントの実行に必要な許可を追加します。
外部ロケーションを表すネットワークルールを作成します。
必要な権限など、外部アクセスにおけるネットワークルールのロールについては、 外部ネットワークロケーションを表すネットワークルールの作成 をご参照ください。
CREATE OR REPLACE NETWORK RULE google_apis_network_rule MODE = EGRESS TYPE = HOST_PORT VALUE_LIST = ('translation.googleapis.com');
google_apis_network_rule
ネットワークルールで指定された外部ネットワークロケーションとの認証に必要な OAuth 認証情報を保持するセキュリティ統合を作成します。必要な権限など、コマンドに関する参考情報については、 CREATE SECURITY INTEGRATION (外部 API 認証) をご参照ください。
CREATE OR REPLACE SECURITY INTEGRATION google_translate_oauth TYPE = API_AUTHENTICATION AUTH_TYPE = OAUTH2 OAUTH_CLIENT_ID = 'my-client-id' OAUTH_CLIENT_SECRET = 'my-client-secret' OAUTH_TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token' OAUTH_AUTHORIZATION_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth' OAUTH_ALLOWED_SCOPES = ('https://www.googleapis.com/auth/cloud-platform') ENABLED = TRUE;
google_translate_oauth
セキュリティ統合に含まれる認証情報を表すシークレットを作成します。必要な権限など、外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。
シークレットは、 OAUTH_REFRESH_TOKEN パラメーターでリフレッシュトークンを指定する必要があります。サービスプロバイダー(この場合はGoogle Cloud Translation API サービス)からリフレッシュトークンを取得するには、プロバイダーが提供する方法を使用するか、Snowflakeのシステム関数を使用します。
リフレッシュトークンでシークレットを作成するには、以下のようにGoogle OAuth PlaygroundまたはSnowflakeシステム関数の いずれか を使用します。
Snowflakeシステム関数
CREATE SECRET を実行してシークレットを作成します。後のステップで、これをリフレッシュトークンで更新します。
USE DATABASE my_db; USE SCHEMA secret_schema; CREATE OR REPLACE SECRET oauth_token TYPE = oauth2 API_AUTHENTICATION = google_translate_oauth;
SYSTEM$START_OAUTH_FLOW 関数を実行して URL を取得し、その引数に以前に作成したシークレットの名前を指定してリフレッシュトークンを取得することができます。
CALL SYSTEM$START_OAUTH_FLOW( 'my_db.secret_schema.oauth_token' );
この関数は URL を生成し、 OAuth 同意プロセスを完了するために使用できます。
ブラウザーで、生成された URL にアクセスし、 OAuth2 同意プロセスを完了します。終了したら、ブラウザーをプロセスの最終ページで開いたままにしておきます。
ブラウザーのアドレスバーから、同意プロセスの最終ページの URL にあるクエスチョンマーク以降のテキストをすべてコピーします。
ブラウザーのアドレスバーからコピーしたパラメーターを引数に指定して、 SYSTEM$FINISH_OAUTH_FLOW 関数を実行します。
これによってリフレッシュトークンでシークレットが更新されます。
必ず SYSTEM$FINISH_OAUTH_FLOW を SYSTEM$START_OAUTH_FLOW と同じセッションで実行してください。SYSTEMFINISH_OAUTH_FLOW は SYSTEM$START_OAUTH_FLOW で指定したシークレットを OAuth サーバーから取得したアクセストークンとリフレッシュトークンで更新します。
CALL SYSTEM$FINISH_OAUTH_FLOW( 'state=<remaining_url_text>' );
Google OAuth Playground
GoogleOAuth Playground で、ステップ1で指定したようにCloud Translation API を選択して認証します。
ステップ2で exchange authorization code for tokens をクリックし、 refresh token トークン値をコピーします。
CREATE SECRET を実行して、コピーしたリフレッシュトークン値を指定するシークレットを作成します。
必要な権限など、外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。
CREATE OR REPLACE SECRET oauth_token TYPE = oauth2 API_AUTHENTICATION = google_translate_oauth OAUTH_REFRESH_TOKEN = 'my-refresh-token';
ネットワークルールとシークレットを使用して外部アクセス統合を作成します。
必要な権限など、外部アクセス統合のロールについては、 外部アクセス統合の作成 をご参照ください。
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION google_apis_access_integration ALLOWED_NETWORK_RULES = (google_apis_network_rule) ALLOWED_AUTHENTICATION_SECRETS = (oauth_token) ENABLED = TRUE;
統合を使用する UDF またはプロシージャを作成する必要があるユーザーに割り当てる
developer
ロールを作成します。CREATE OR REPLACE ROLE developer; CREATE OR REPLACE ROLE user;
外部アクセス用のオブジェクトを使用する UDF を作成するために必要な権限を
developer
ロールに付与します。これには、次が含まれます。シークレットに対する READ 権限。
シークレットを含むスキーマに対する USAGE 権限。
統合に対する USAGE 権限。
GRANT READ ON SECRET oauth_token TO ROLE developer; GRANT USAGE ON SCHEMA secret_schema TO ROLE developer; GRANT USAGE ON INTEGRATION google_apis_access_integration TO ROLE developer;
指定されたテキストを指定された言語のフレーズに翻訳する UDF
google_translate_python
を作成します。詳細については、 関数またはプロシージャでの外部アクセス統合の使用 をご参照ください。USE ROLE developer; CREATE OR REPLACE FUNCTION google_translate_python(sentence STRING, language STRING) RETURNS STRING LANGUAGE PYTHON RUNTIME_VERSION = 3.8 HANDLER = 'get_translation' EXTERNAL_ACCESS_INTEGRATIONS = (google_apis_access_integration) PACKAGES = ('snowflake-snowpark-python','requests') SECRETS = ('cred' = oauth_token ) AS $$ import _snowflake import requests import json session = requests.Session() def get_translation(sentence, language): token = _snowflake.get_oauth_access_token('cred') url = "https://translation.googleapis.com/language/translate/v2" data = {'q': sentence,'target': language} response = session.post(url, json = data, headers = {"Authorization": "Bearer " + token}) return response.json()['data']['translations'][0]['translatedText'] $$;
USAGE 権限を
google_translate_python
関数に付与して、user
ロールを持つ人がその関数を呼び出せるようにします。GRANT USAGE ON FUNCTION google_translate_python(string, string) TO ROLE user;
フレーズを翻訳するには
google_translate_python
関数を実行します。USE ROLE user; SELECT google_translate_python('Happy Thursday!', 'zh-CN');
これは以下のような出力を生成します。
------------------------------------------------------- | GOOGLE_TRANSLATE_PYTHON('HAPPY THURSDAY!', 'ZH-CN') | ------------------------------------------------------- | 快乐星期四! | -------------------------------------------------------
外部ラムダ関数へのアクセス¶
以下のステップでは、Snowflakeの外部ラムダ関数にアクセスするための外部アクセス統合を作成するサンプルコードを示します。この例では外部エンドポイント自体のプレースホルダーを使用していますが、例えば REST サービスエンドポイントで利用可能な関数でも構いません。
外部アクセスは ベクトル化されたPython UDF で使用され、データを含むPandas DataFrame を受け取ります。
外部ロケーション
my_external_service
を表すネットワークルールlambda_network_rule
を作成します(ここでは、外部エンドポイントのロケーションのプレースホルダー値です)。外部アクセスにおけるネットワークルールのロールについては、 外部ネットワークロケーションを表すネットワークルールの作成 をご参照ください。
CREATE OR REPLACE NETWORK RULE lambda_network_rule MODE = EGRESS TYPE = HOST_PORT VALUE_LIST = ('my_external_service');
外部サービスが必要とする認証情報を表すシークレットを作成します。
この例の後のハンドラーコードは、Python用のSnowflake API を使用してシークレットから認証情報を取得します。
外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。
CREATE OR REPLACE SECRET secret_password TYPE = PASSWORD USERNAME = 'my_user_name' PASSWORD = 'my_password';
developer
ロールを作成し、そのロールにシークレットの READ 権限を付与します。このロールは、シークレットを使用する UDF またはプロシージャを作成する必要があるユーザに割り当てられます。また、ユーザが関数を呼び出すために使用するロールを作成します。
CREATE OR REPLACE ROLE developer; CREATE OR REPLACE ROLE user;
外部アクセス用のオブジェクトを使用する UDF を作成するために必要な権限を
developer
ロールに付与します。これには、次が含まれます。シークレットに対する READ 権限。
シークレットを含むスキーマに対する USAGE 権限。
GRANT READ ON SECRET secret_password TO ROLE developer; GRANT USAGE ON SCHEMA secret_schema TO ROLE developer;
外部アクセス統合を作成し、作成したネットワークルールとシークレットを使用して外部エンドポイントと認証情報を指定します。
必要な権限など、外部アクセス統合のロールについては、 外部アクセス統合の作成 をご参照ください。
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION lambda_external_access_integration ALLOWED_NETWORK_RULES = (lambda_network_rule) ALLOWED_AUTHENTICATION_SECRETS = (secret_password) ENABLED = TRUE;
Pandas DataFrame として受信したデータを処理するために、外部ネットワークロケーションにアクセスする ベクトル化された Python UDF
return_double_column
を作成します。UDF での外部アクセスの使用の詳細については、 関数またはプロシージャでの外部アクセス統合の使用 をご参照ください。
CREATE OR REPLACE FUNCTION return_double_column(x int) RETURNS INT LANGUAGE PYTHON EXTERNAL_ACCESS_INTEGRATIONS = (lambda_external_access_integration) SECRETS = ('cred' = secret_password) RUNTIME_VERSION = 3.8 HANDLER = 'return_first_column' PACKAGES = ('pandas', 'requests') AS $$ import pandas import numpy as np import json import requests import base64 import _snowflake from _snowflake import vectorized from requests.auth import HTTPBasicAuth from requests.adapters import HTTPAdapter from requests.packages.urllib3.util.retry import Retry session = requests.Session() retries = Retry(total=10, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504], allowed_methods = None) session.mount('https://', HTTPAdapter(max_retries=retries)) @vectorized(input=pandas.DataFrame) def return_first_column(df): request_rows = [] df.iloc[:,0] = df.iloc[:,0].astype(int) request_rows = np.column_stack([df.index, df.iloc[:,0]]).tolist() request_payload = {"data" : request_rows} username_password_object = _snowflake.get_username_password('cred'); basic = HTTPBasicAuth(username_password_object.username, username_password_object.password) url = 'my_external_service' response = session.post(url, json=request_payload, auth=basic) response.raise_for_status() response_payload = json.loads(response.text) response_rows = response_payload["data"] return pandas.DataFrame(response_rows)[1] $$;
USAGE 権限を
return_double_column
関数に付与して、user
ロールを持つ人がその関数を呼び出せるようにします。GRANT USAGE ON FUNCTION return_double_column(int) TO ROLE user;
return_double_column
関数を実行し、外部エンドポイントにリクエストを行います。以下の例のコードは、2列のテーブルを作成し、4バイト整数を含む100,000,000行を挿入します。次にコードは
return_double_column
関数を実行し、外部エンドポイントによる処理のためにa
列から値を渡します。CREATE OR REPLACE TABLE t1 (a INT, b INT); INSERT INTO t1 SELECT SEQ4(), SEQ4() FROM TABLE(GENERATOR(ROWCOUNT => 100000000)); SELECT return_double_column(a) AS retval FROM t1 ORDER BY retval;