アプリケーションパッケージに請求対象イベントを追加する¶
Snowflake Native App にCustom Event Billingを使用すると、既存の従量制料金プランに加えて、特定の種類のアプリケーション使用量に対して課金することができます。これを設定するには、2つの高レベルなステップを実行する必要があります。
このトピックのステップに従って、請求対象イベントを発行するようにアプリケーションパッケージを設定します。
コンシューマーに Snowflake Native App を公開するために使用するリストには、 請求対象イベントのある従量制料金プランを選択 します。
このトピックでは、 SYSTEM$CREATE_BILLING_EVENT システム関数を使用して、請求対象イベントを発行するようにアプリケーションパッケージを設定する方法について説明します。
アプリケーションパッケージ内の請求対象イベントの概要¶
特定の使用イベントに応答して請求対象イベントを発行するようにアプリケーションパッケージを設定すると、 Snowflake Native App の使用量に応じてコンシューマーに課金することができます。
たとえば、請求対象イベントを追加して、 Snowflake Native App のストアドプロシージャを呼び出すたびに、コンシューマーに特定の金額を請求することができます。
アプリケーションパッケージに請求対象イベントを追加するには、以下を実行します。
ストアドプロシージャを作成して、 SYSTEM$CREATE_BILLING_EVENT システム関数の呼び出しをトリガーする使用イベントを定義します。
注釈
この段階では、システム関数の出力をテストすることはできません。このシステム関数は、コンシューマーアカウントにインストールされた Snowflake Native App からのみ呼び出すことができます。
これらのストアドプロシージャをアプリケーションパッケージのセットアップスクリプトに追加します。
重要
Snowflakeは、このトピックの例で概説されているように、アプリケーションのストアドプロシージャ内でシステム関数を呼び出すことによって発行する請求対象イベントをサポートしています。
Snowflakeは、コンシューマーアクティビティを出力するテーブルまたはユーザー定義関数の出力を使用するメソッド、またはイベントテーブルにログ記録されたテレメトリを使用するメソッドなど、請求対象イベントの基本料金を計算する他のメソッドをサポートしていません。
提案された実装がサポートされるかどうか不明な場合は、Snowflakeのアカウント担当者にお問い合わせください。
請求対象イベントの例¶
このセクションの例では、一般的な請求シナリオに対して請求対象イベントを発行するストアドプロシージャを作成する方法を示します。これらの各例は、 SYSTEM$CREATE_BILLING_EVENT システム関数を呼び出す で定義されている createBillingEvent
関数を呼び出します。
SYSTEM$CREATE_BILLING_EVENT システム関数を呼び出す¶
次の例は、 SYSTEM$CREATE_BILLING_EVENT システム関数を呼び出すために、ストアドプロシージャ内にラッパー関数を作成する方法を示しています。
注釈
このシステム関数は、 JavaScript、Python、またはJavaで記述されたストアドプロシージャで呼び出すことができます。
この例では、データベース db_1
とスキーマ public
に custom_event_billing
という名前の JavaScript ストアドプロシージャを作成します。このストアドプロシージャは、 SYSTEM$CREATE_BILLING_EVENT システム関数が期待する型付きパラメーターに対応する引数を取る、 createBillingEvent
というヘルパー関数を作成します。
パラメーターと必要な型の詳細については、 SYSTEM$CREATE_BILLING_EVENT をご参照ください。
CREATE OR REPLACE PROCEDURE db_1.public.custom_event_billing()
RETURNS NULL
LANGUAGE JAVASCRIPT
AS
$$
/**
* Helper method to add a billable event
* Format timestamps as Unix timestamps in milliseconds
*/
function createBillingEvent(className, subclassName, startTimestampVal, timestampVal, baseCharge, objects, additionalInfo) {
try {
var res = snowflake.createStatement({
sqlText: `SELECT SYSTEM$CREATE_BILLING_EVENT('${className}',
'${subclassName}',
${startTimestampVal},
${timestampVal},
${baseCharge},
'${objects}',
'${additionalInfo}')`
}).execute();
res.next();
return res.getColumnValue(1);
} catch(err) {
return err.message;
}
}
$$;
このトピックの例では、このヘルパー関数を呼び出します。
例: ストアドプロシージャへの呼び出しに基づく課金¶
以下の例では、 Snowflake Native App でコンシューマーがストアドプロシージャを呼び出すと、請求対象イベントが発行するようにストアドプロシージャを作成する方法を示します。
このサンプルコードを、ヘルパー関数を定義するのと同じストアドプロシージャ内のセットアップスクリプトに追加します。
...
//
// Send a billable event when a stored procedure is called.
//
var event_ts = Date.now();
var billing_quantity = 1.0;
var base_charge = billing_quantity;
var objects = "[ \"db_1.public.procedure_1\" ]";
var retVal = createBillingEvent("PROCEDURE_CALL", "", event_ts, event_ts, base_charge, objects, "");
// Run the rest of the procedure ...
$$;
このコード例では、 PROCEDURE_CALL
というクラス名と、 1.0
という基本料金で請求対象イベントを発行させるために、 createBillingEvent
関数を呼び出すストアドプロシージャを作成します。
注釈
createBillingEvent
関数に渡される引数の型は、 SYSTEM$CREATE_BILLING_EVENT システム関数が期待する型付きパラメーターに対応している必要があります。
例: Snowflake Native Appで消費された行に基づく課金¶
以下の例では、コンシューマーアカウントのテーブル内で消費された行数に基づいて請求対象イベントを発行するストアドプロシージャを作成する方法を示します。
このサンプルコードを、ヘルパー関数を定義するのと同じストアドプロシージャ内のセットアップスクリプトに追加します。
...
// Run a query and get the number of rows in the result
var select_query = "select i from db_1.public.t1";
res = snowflake.execute ({sqlText: select_query});
res.next();
//
// Send a billable event for rows returned from the select query
//
var event_ts = Date.now();
var billing_quantity = 2.5;
var base_charge = res.getRowcount() * billing_quantity;
var objects = "[ \"db_1.public.t1\" ]";
createBillingEvent("ROWS_CONSUMED", "", event_ts, event_ts, base_charge, objects, "");
// Run the rest of the procedure ...
$$;
このコード例では、 ROWS_CONSUMED
というクラス名、また 2.5
という基本料金にコンシューマーアカウントの db_1.public.t1
テーブルの行数を掛けた計算値を持つ請求対象イベントを発行するために、 createBillingEvent
関数を呼び出すストアドプロシージャを作成します。
注釈
createBillingEvent
関数に渡される引数の型は、 SYSTEM$CREATE_BILLING_EVENT システム関数が期待する型付きパラメーターに対応している必要があります。
例: インジェストされた行数に基づく課金¶
次の例は、テーブルにインジェストされた行数に基づいて請求対象イベントを発行するストアドプロシージャを作成する方法を示しています。
このサンプルコードを、ヘルパー関数を定義するのと同じストアドプロシージャ内のセットアップスクリプトに追加します。
...
// Run the merge query
var merge_query = "MERGE INTO target_table USING source_table ON target_table.i = source_table.i
WHEN MATCHED THEN UPDATE SET target_table.j = source_table.j
WHEN NOT MATCHED
THEN INSERT (i, j)
VALUES (source_table.i, source_table.j)";
res = snowflake.execute ({sqlText: merge_query});
res.next();
// rows ingested = rows inserted + rows updated
var numRowsIngested = res.getColumnValue(1) + res.getColumnValue(2);
//
// Send a billable event for rows changed by the merge query
//
var event_ts = Date.now();
var billing_quantity = 2.5;
var base_charge = numRowsIngested * billing_quantity;
var objects = "[ \"db_1.public.target_table\" ]";
createBillingEvent("ROWS_CHANGED", "", event_ts, event_ts, base_charge, objects, "");
// Run the rest of the procedure ...
$$;
このコード例では、 createBillingEvent
関数を呼び出して、 ROWS_CHANGED
というクラス名、また 2.5
に db_1.target_table
テーブルでインジェストされた行数を掛けた基本料金を計算した請求対象イベントを発行するストアドプロシージャを作成します。
注釈
createBillingEvent
関数に渡される引数の型は、 SYSTEM$CREATE_BILLING_EVENT システム関数が期待する型付きパラメーターに対応している必要があります。
例: 月ごとのアクティブ行に基づく課金¶
毎月のアクティブ行数とは、暦月内に初めて挿入または更新された行数のことです。プロバイダーの中には、このメトリックを使用して、1か月間に更新された一意の行に対してのみコンシューマーに課金するところもあります。この例を変更して、一意のユーザーをカウントしたり、一意のデータロード場所を識別して基本料金を決定したりすることができます。
次の例は、毎月のアクティブ行数に基づいて請求対象イベントを発行するストアドプロシージャの作成方法を示しています。このサンプルコードを、ヘルパー関数を定義するのと同じストアドプロシージャ内のセットアップスクリプトに追加します。
...
//
// Get monthly active rows
//
var monthly_active_rows_query = "
SELECT
count(*)
FROM
source_table
WHERE
source_table.i not in
(
SELECT
i
FROM
target_table
WHERE
updated_on >= DATE_TRUNC('MONTH', CURRENT_TIMESTAMP)
)";
res = snowflake.execute ({sqlText: monthly_active_rows_query});
res.next();
var monthlyActiveRows = parseInt(res.getColumnValue(1));
//
// Run the merge query and update the updated_on values for the rows
//
var merge_query = "
MERGE INTO
target_table
USING
source_table
ON
target_table.i = source_table.i
WHEN MATCHED THEN
UPDATE SET target_table.j = source_table.j
,target_table.updated_on = current_timestamp
WHEN NOT MATCHED THEN
INSERT (i, j, updated_on) VALUES (source_table.i, source_table.j, current_timestamp)";
res = snowflake.execute ({sqlText: merge_query});
res.next();
//
// Emit a billable event for monthly active rows changed by the merge query
//
var event_ts = Date.now();
var billing_quantity = 0.02
var base_charge = monthlyActiveRows * billing_quantity;
var objects = "[ \"db_1.public.target_table\" ]";
createBillingEvent("MONTHLY_ACTIVE_ROWS", "", event_ts, event_ts, base_charge, objects, "");
// Run the rest of the procedure ...
$$;
このコード例では、マージクエリを使用して一意の行を識別し、毎月のアクティブ行数を決定するストアドプロシージャを作成します。そしてこの例では、 monthlyActiveRows
変数の値と billing_quantity
を使用して基本料金を計算します。基本料金は、 createBillingEvent
関数に渡されます。
注釈
createBillingEvent
関数に渡される引数の型は、 SYSTEM$CREATE_BILLING_EVENT システム関数が期待する型付きパラメーターに対応している必要があります。
セットアップスクリプトで、 SYSTEM$CREATE_BILLING_EVENT システム関数を呼び出すストアドプロシージャ の後に、このストアドプロシージャを追加します。
Snowpark Pythonの例: 消費された行に基づく課金¶
ストアドプロシージャをSnowpark Pythonで記述し、 Snowflake Native App によって消費された行に基づいて課金する場合は、以下の例を使用します。
CREATE OR REPLACE PROCEDURE app_schema.billing_event_rows()
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = '3.9'
PACKAGES = ('snowflake-snowpark-python')
HANDLER = 'run'
EXECUTE AS OWNER
AS $$
import time
# Helper method that calls the system function for billing
def createBillingEvent(session, class_name, subclass_name, start_timestamp, timestamp, base_charge, objects, additional_info):
session.sql(f"SELECT SYSTEM$CREATE_BILLING_EVENT('{class_name}', '{subclass_name}', {start_timestamp}, {timestamp}, {base_charge}, '{objects}', '{additional_info}')").collect()
return "Success"
# Handler function for the stored procedure
def run(session):
# insert code to identify monthly active rows and calculate a charge
try:
# Run a query to select rows from a table
query = "select i from db_1.public.t1"
res = session.sql(query).collect()
# Define the price to charge per row
billing_quantity = 2.5
# Calculate the base charge based on number of rows in the result
charge = len(res) * billing_quantity
# Current time in Unix timestamp (epoch) time in milliseconds
current_time_epoch = int(time.time() * 1000)
return createBillingEvent(session, 'ROWS_CONSUMED', '', current_time_epoch, current_time_epoch, charge, '["billing_event_rows"]', '')
except Exception as ex:
return "Error " + ex
$$;
このコード例では、 SYSTEM$CREATE_BILLING_EVENT システム関数を呼び出すヘルパーメソッドを定義するストアドプロシージャ、またそのヘルパーメソッド createBillingEvent
を呼び出して、 ROWS_CONSUMED
というクラス名、また 2.5
US ドルという価格にコンシューマーアカウントの db_1.public.t1
テーブルの行数を乗じて計算される基本料金を持つ請求対象イベントを発行するメソッドを作成します。
注釈
createBillingEvent
関数に渡される引数の型は、 SYSTEM$CREATE_BILLING_EVENT システム関数が期待する型付きパラメーターに対応している必要があります。
Custom Event Billingをテストする¶
Custom Event Billingを正しく設定し、請求対象イベントが期待通りに使用イベントに対して発行することを確認するには、以下を実行します。
アプリケーションパッケージを更新します。
セットアップスクリプトを更新して、請求対象イベントを発行するストアドプロシージャを含めます。
新しいセットアップスクリプトでアプリケーションパッケージを更新します。
アプリケーションパッケージのバージョンとリリースディレクティブを更新します。
アクセス可能な組織内のコンシューマーアカウントとアプリケーションパッケージを共有します。
料金プランとしてCustom Event Billing を追加します。
コンシューマーアカウントと共有します。
Snowsight を使用して、コンシューマーアカウントにサインインします。
Snowflake Native App をインストールします。
ストアドプロシージャが請求対象イベントを正常に発行する ことを確認します。
リストが適切に設定されている ことを確認します。
注釈
Custom Event Billingをテストする場合は、 支払い方法を設定する 必要がありますが、組織内での利用には課金されません。
ストアドプロシージャが請求対象イベントを発行するかどうかを検証する¶
リストを共有したコンシューマーカウントにサインインした状態で、 Snowflake Native App に追加したストアドプロシージャを呼び出します。
たとえば、 毎月のアクティブ行に基づく請求 のために作成されたストアドプロシージャをテストするには、次を実行します。
Snowsight のコンシューマーアカウントにサインインします。
ワークシートを開き、コンテキストを
db_1.public
に設定します。次の SQL ステートメントを実行します。
CALL merge_procedure()
ストアドプロシージャが
Success
を返せば、コードは機能しています。
注釈
アプリケーションパッケージの作成に使用したプロバイダーアカウントでこれらの SQL コマンドを実行すると、エラーが表示されます。
Custom Event Billing料金プランを検証する¶
Snowflake Native App のコンシューマーエクスペリエンスを検証し、リストとアプリケーションパッケージが適切に設定されていることを確認するには、共有 SNOWFLAKE データベースにある DATA_SHARING_USAGE スキーマの MARKETPLACE_PAID_USAGE_DAILY ビュー をクエリします。
注釈
ビューには遅延があるため、これらのクエリは Snowflake Native App を初めて使用してから最低2日後に実行します。
請求対象イベントが Snowflake Native App とリストによって正常に生成されていることを確認するには、リストを共有したコンシューマーカウントで、以下の SQL ステートメントを実行します。
注釈
PROVIDER_ACCOUNT_NAME と PROVIDER_ORGANIZATION_NAME の値をプロバイダーアカウントの値に置き換えます。
SELECT listing_global_name,
listing_display_name,
charge_type,
charge
FROM SNOWFLAKE.DATA_SHARING_USAGE.MARKETPLACE_PAID_USAGE_DAILY
WHERE charge_type='MONETIZABLE_BILLING_EVENTS'
AND PROVIDER_ACCOUNT_NAME = <account_name>
AND PROVIDER_ORGANIZATION_NAME= <organization_name>;
+---------------------+------------------------+----------------------------+--------+
| LISTING_GLOBAL_NAME | LISTING_DISPLAY_NAME | CHARGE_TYPE | CHARGE |
+---------------------+------------------------+----------------------------+--------+
| AAAA0BBB1CC | Snowy Mountain Listing | MONETIZABLE_BILLING_EVENTS | 18.6 |
+---------------------+------------------------+----------------------------+--------+
リスト料金プランに関連するすべての詳細を確認し、プランがアプリケーションの料金と一致していることを確認するには、リストを共有したコンシューマーアカウントで、次の SQL ステートメントを実行します。
注釈
pp
が先頭に追加されたフィールドは、料金プランの一部としてリストでのみ指定されるフィールドを表します。
SELECT
listing_display_name,
listing_global_name,
be.value:display_name::varchar as class_name,
be.value:class::varchar as class,
units,
be.value:billing_unit::varchar as billing_unit,
unit_price,
charge,
be.value:billing_quantity::float as pp_billing_quantity
FROM
SNOWFLAKE.DATA_SHARING_USAGE.MARKETPLACE_PAID_USAGE_DAILY,
LATERAL FLATTEN(INPUT => pricing_plan:billing_events) be
WHERE
charge_type = 'MONETIZABLE_BILLING_EVENTS'
AND PROVIDER_ACCOUNT_NAME = <account_name>
AND PROVIDER_ORGANIZATION_NAME= <organization_name>;
+------------------------+---------------------+-------------+---------------+-------+--------------+------------+--------+---------------------+
| LISTING_DISPLAY_NAME | LISTING_GLOBAL_NAME | CLASS_NAME | CLASS | UNITS | BILLING_UNIT | UNIT_PRICE | CHARGE | PP_BILLING_QUANTITY |
+------------------------+---------------------+-------------+---------------+-------+--------------+------------+--------+---------------------+
| Snowy Mountain Listing | AAAA0BBB1CC | Active Rows | ROWS_CONSUMED | 18.6 | ROW | 1 | 18.6 | 1 |
+------------------------+---------------------+-------------+---------------+-------+--------------+------------+--------+---------------------+