外部ネットワークアクセスの例

このトピックでは、ユーザー定義関数とプロシージャから外部ネットワークロケーションにアクセスする例を示します。

Google翻訳 API へのアクセス

以下のステップでは、Google翻訳 API にアクセスするための外部アクセス統合を作成するコードを示します。ステップでは、セキュリティの統合と、ステートメントの実行に必要な許可を追加します。

  1. 外部ロケーションを表すネットワークルールを作成します。

    外部アクセスにおけるネットワークルールのロールについては、 外部ネットワークロケーションを表すネットワークルールの作成 をご参照ください。

    CREATE OR REPLACE NETWORK RULE google_apis_network_rule
      MODE = EGRESS
      TYPE = HOST_PORT
      VALUE_LIST = ('translation.googleapis.com');
    
    Copy
  2. 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;
    
    Copy
  3. google_translate_oauth セキュリティ統合に含まれる認証情報を表すシークレットを作成します。

    外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。

    OAUTH_REFRESH_TOKEN 値には、サービスプロバイダーから取得したリフレッシュトークンを指定する必要があります(この場合は、Google Cloud Translation APIサービス用)。例えば、リフレッシュトークンを取得するには、次を使用することができます。

    • Google OAuth Playground。ステップ1で、Cloud Translation API を選択して承認します。ステップ2で exchange authorization code for tokens をクリックし、 refresh token トークン値をコピーします。

    CREATE OR REPLACE SECRET oauth_token
      TYPE = oauth2
      API_AUTHENTICATION = google_translate_oauth
      OAUTH_REFRESH_TOKEN = 'my-refresh-token';
    
    Copy
  4. developer ロールを作成し、そのロールにシークレットの READ 権限を付与します。このロールは、シークレットを使用する UDF またはプロシージャを作成する必要があるユーザに割り当てられます。

    また、ユーザが関数を呼び出すために使用するロールを作成します。

    USE ROLE USERADMIN;
    CREATE OR REPLACE ROLE developer;
    CREATE OR REPLACE ROLE user;
    
    Copy

    developer ロールに READ 権限を付与します。

    GRANT READ ON SECRET oauth_token TO ROLE developer;
    
    Copy
  5. 外部アクセス統合の作成 に記載されているように、ネットワークルールとシークレットを使用して外部アクセス統合を作成します。

    このコマンドを実行するには、 CREATE INTEGRATION 権限を持つロールを使用する必要があります(デフォルトでは ACCOUNTADMIN ロールが持っています)。

    USE ROLE ACCOUNTADMIN;
    
    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION google_apis_access_integration
      ALLOWED_NETWORK_RULES = (google_apis_network_rule)
      ALLOWED_AUTHENTICATION_SECRETS = (oauth_token)
      ENABLED = TRUE;
    
    Copy
  6. UDF の開発者が使えるように、統合に対する USAGE 権限を developer ロールに付与します。UDF またはプロシージャの外部ネットワークロケーションへのアクセスに統合を使用するには、ユーザーは統合に USAGE 権限を持つロールを使用する必要があります。

    GRANT USAGE ON INTEGRATION google_apis_access_integration TO ROLE developer;
    
    Copy
  7. 指定されたテキストを指定された言語のフレーズに翻訳する 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']
    $$;
    
    Copy
  8. USAGE 権限を google_translate_python 関数に付与して、ユーザーロールを持つ人がその関数を呼び出せるようにします。

    GRANT USAGE ON FUNCTION google_translate_python(string, string) TO ROLE user;
    
    Copy
  9. フレーズを翻訳するには google_translate_python 関数を実行します。

    USE ROLE user;
    SELECT google_translate_python('Happy Thursday!', 'zh-CN');
    
    Copy

    これは以下のような出力を生成します。

    -------------------------------------------------------
    | GOOGLE_TRANSLATE_PYTHON('HAPPY THURSDAY!', 'ZH-CN') |
    -------------------------------------------------------
    | 快乐星期四!                                          |
    -------------------------------------------------------
    

外部ラムダ関数へのアクセス

以下のステップでは、Snowflakeの外部ラムダ関数にアクセスするための外部アクセス統合を作成するサンプルコードを示します。この例では外部エンドポイント自体のプレースホルダーを使用していますが、例えば REST サービスエンドポイントで利用可能な関数でも構いません。

外部アクセスは ベクトル化されたPython UDF で使用され、データを含むPandas DataFrame を受け取ります。

  1. 外部ロケーション my_external_service を表すネットワークルール lambda_network_rule を作成します(ここでは、外部エンドポイントのロケーションのプレースホルダー値です)。

    外部アクセスにおけるネットワークルールのロールについては、 外部ネットワークロケーションを表すネットワークルールの作成 をご参照ください。

    CREATE OR REPLACE NETWORK RULE lambda_network_rule
      MODE = EGRESS
      TYPE = HOST_PORT
      VALUE_LIST = ('my_external_service');
    
    Copy
  2. 外部サービスが必要とする認証情報を表すシークレットを作成します。

    この例の後のハンドラーコードは、Python用のSnowflake API を使用してシークレットから認証情報を取得します。

    外部アクセスにおけるシークレットのロールについては、 認証情報を表すシークレットの作成 をご参照ください。

    CREATE OR REPLACE SECRET secret_password
      TYPE = PASSWORD
      USERNAME = 'my_user_name'
      PASSWORD = 'my_password';
    
    Copy
  3. developer ロールを作成し、そのロールにシークレットの READ 権限を付与します。このロールは、シークレットを使用する UDF またはプロシージャを作成する必要があるユーザに割り当てられます。

    また、ユーザが関数を呼び出すために使用するロールを作成します。

    USE ROLE USERADMIN;
    
    CREATE OR REPLACE ROLE developer;
    CREATE OR REPLACE ROLE user;
    
    Copy

    シークレットの READ 権限を developer ロールに付与します。

    GRANT READ ON SECRET secret_password TO ROLE developer;
    
    Copy
  4. 外部アクセス統合を作成し、作成したネットワークルールとシークレットを使用して外部エンドポイントと認証情報を指定します。

    このコマンドを実行するには、 CREATE INTEGRATION 権限を持つロールを使用する必要があります(デフォルトでは ACCOUNTADMIN ロールが持っています)。

    統合の作成の詳細については、 外部アクセス統合の作成 をご参照ください。

    USE ROLE ACCOUNTADMIN;
    
    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION lambda_external_access_integration
      ALLOWED_NETWORK_RULES = (lambda_network_rule)
      ALLOWED_AUTHENTICATION_SECRETS = (secret_password)
      ENABLED = TRUE;
    
    Copy
  5. 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]
    $$;
    
    Copy
  6. USAGE 権限を return_double_column 関数に付与して、 user ロールを持つ人がその関数を呼び出せるようにします。

    GRANT USAGE ON FUNCTION return_double_column(int) TO ROLE user;
    
    Copy
  7. 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;
    
    Copy