다단계 흐름 디자인하기¶
개요¶
Most clean room usage involves running a single SQL query against one or more tables in a clean room and displaying the results in the response. However, there are many use cases where you might want to break up your flow into several steps, which can be run sequentially or individually, and can involve calling Python code to process (or pre-process) data. Examples include a machine learning flow where the model is trained once against a data set and then run multiple times against varying input data, either singly or in batches.
Clean Rooms에는 이러한 고급 시나리오를 가능하게 하는 몇 가지 메커니즘이 있습니다.
템플릿 체인: 템플릿 체인 은 각 템플릿의 출력을 다음 템플릿의 입력으로 사용하여 특정 순서로 템플릿 세트를 실행합니다. 체인의 첫 번째 템플릿에 대한 입력은 사용자가 제공하고, 체인의 마지막 템플릿의 출력은 사용자에게 반환됩니다.
Internal tables: Your template or custom internal functions can create persistent tables within a clean room. These tables behave like linked tables in that they are accessible to templates or custom uploaded code. Internal tables are useful for maintaining state or data; in the machine learning example, the training data is saved in an internal table that is used by internal functions. Just as with linked tables, these tables can be accessed only by templates or uploaded code inside the clean room. Storing intermediary data in internal tables is more efficient than passing large blocks of information into and out of the clean room using templates.
사용자 지정 내부 함수: 클린룸 내에서 템플릿으로 호출할 수 있는 사용자 지정 함수를 클린룸 내에서 정의할 수 있습니다. 클린룸에서 함수를 정의하려면 PythonUDFs 또는 UDTFs 클린룸에서 함수를 정의할 수 있습니다. 이러한 함수는 클린룸 내의 템플릿에서만 호출할 수 있습니다.
참고
A unifying principle of all techniques is that tables and functions are accessed or run using a template. You cannot access a clean room internal table, run a custom clean room function, or access an internal clean room endpoint directly, only by using a template.
내부 Clean Room 테이블¶
You can create tables inside a clean room using SQL or Python to store intermediary results, or for persistent storage for the user or your internal functions (for example, to save training data that is used for multiple runs). These tables behave the same as linked tables, with the following notes:
Internal tables are created using a clean room template or a UDF/UDTF, and have no linkage to outside tables.
Internal tables are created in the
cleanroomnamespace.You can set row and column policies on internal tables after you create them.
If the table name is dynamic, and the table is accessed by other templates or code, return the name of the table to the user so the user can pass the dynamic table name to any other templates that need to access that table.
다음은 내부 테이블을 만드는 몇 가지 예입니다.
JinjaSQL 템플릿은 내부 테이블을 만들 수 있는데, 이 작업은 활성화 의 일부 유형에서 수행됩니다.
This example returns the table name so that it can be passed in as a parameter to other templates.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
$cleanroom_name,
$template_name,
$$
BEGIN
CREATE OR REPLACE TABLE cleanroom.analysis_results AS
SELECT count(*) AS ITEM_COUNT, c.status, c.age_band
FROM IDENTIFIER({{ my_table[0] }}) AS c
JOIN IDENTIFIER({{ source_table[0] }}) AS p
ON {{ c_join_col | sqlsafe | activation_policy }} = {{ p_join_col | sqlsafe | activation_policy }}
GROUP BY c.status, c.age_band
ORDER BY c.age_band;
RETURN 'analysis_results';
END;
$$);
UDF 는 내부 테이블을 만들 수 있습니다. 일반적으로 Python에서 SQL 을 실행하면 됩니다.
# Snippet of Python UDF to save results to an internal table.
table_name = f'cleanroom.results'
session.sql(f"""
CREATE OR REPLACE TABLE {table_name} AS (
WITH joint_data AS (
SELECT
date,
p.hashed_email AS hem,
impression_id
FROM {source_table} p
)
SELECT
date,
COUNT(DISTINCT hem) AS reach,
COUNT(DISTINCT impression_id) AS num_impressions
FROM joint_data
GROUP BY date
ORDER BY date
);
""").collect()
# Snippet of container services Python code to create an internal results table.
# 'cleanroom' table name prefix is added using the schema parameter when the table is created.
@app.post("/score")
def score():
... omitted content ...
df = pd.DataFrame({
"ID": ids,
"SCORE": scores
})
table = "LOOKALIKE_RESULTS"
session.write_pandas(df, table, schema="CLEANROOM", auto_create_table=True, overwrite=True)
end_time = time.perf_counter()
execution_time = end_time - start_time
response = make_json_response([[0, {"results_table": table, "size": len(ids), "execution_time": round(execution_time, 2)}]])
return response
템플릿이나 코드로 액세스해야 하는 내부 테이블을 생성할 때 상수 테이블 이름을 사용하거나 테이블 이름을 동적으로 지정하고 사용자에게 테이블 이름을 반환한 다음 사용자에게 테이블 이름을 결과 함수에 전달할 수 있습니다.
다음은 결과를 저장하는 데 사용되는 동적으로 이름이 지정된 테이블의 예입니다. 사용자는 데이터를 생성하고 테이블 이름을 얻기 위해 한 번, 결과를 보기 위해 두 번 호출합니다.
공급자 템플릿은
reach_impression_regressionUDF 를 호출하여 데이터를 처리합니다(cleanroom접두사는 이것이 UDF 임을 나타냄). UDF 는 내부 테이블 접두사 이름을 템플릿에 반환하고, 템플릿은 이를 호출자에게 반환합니다.-- This template calls a UDF uploaded by a collaborator. -- The UDF takes two input tables as parameters. CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template( $cleanroom_name, 'prod_calculate_regression', $$ CALL cleanroom.reach_impression_regression({{ source_table[0] }}, {{ my_table[0] | default('NONE') }}); $$ );
The Python UDF generates the internal table and returns the generated table name to the template caller.
def main(session, source_table, my_table): ... table = f'results_{suffix}'.upper() retval_df = session.write_pandas(regression_output, table, schema = 'CLEANROOM', auto_create_table = True) return f'Done, results have been written to the following table: {table}'
The provider template accepts a table name passed in and displays the contents of that table. Note how the table is always accessed from the
cleanroomnamespace.CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template( $cleanroom_name, 'prod_get_results', $$ SELECT * FROM cleanroom.{{ results_table | sqlsafe }}; $$ );
The consumer calls the template, passing in the table name.
CALL samooha_by_snowflake_local_db.consumer.run_analysis( $cleanroom_name, 'prod_get_results', [], [], object_construct( 'results_table', $table_name ) );
사용자 지정 함수 트리거하기¶
사용자 지정 함수는 Clean Room에서 템플릿 또는 코드(UDF, UDTF 또는 컨테이너 서비스 엔드포인트)로 호출할 수 있습니다. 모든 공동 작업자가 업로드한 함수는 다른 공동 작업자의 템플릿이나 코드를 통해 액세스할 수 있습니다.
Clean Room 함수는 항상 적절한 네임스페이스로 범위를 지정하여 호출해야 합니다.
사용자 지정 UDF/UDTF 함수를 호출할 경우
cleanroom.function_name임베디드 Snowpark Container Service 함수로 노출된 함수를 호출할 경우
service_functions.function_name.
다음은 템플릿에서 사용자 지정 UDF 및 사용자 지정 컨테이너 서비스 엔드포인트를 호출하는 예제입니다.
템플릿은 cleanroom 범위를 사용하여 UDF 또는 UDTF에 액세스합니다.
-- Template to generate results. Calls the UDF 'my_function', which
-- generates a results table inside the clean room called 'results'.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
$cleanroom_name,
'generate_results_template',
$$
CALL cleanroom.my_function({{ source_table[0] }}, {{ my_table[0] | default('NONE') }});
$$
);
템플릿은 service_functions 범위를 사용하여 컨테이너 서비스 함수에 액세스합니다.
-- Template to trigger training data generation.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
$cleanroom_name,
'lal_train',
$$
SELECT service_functions.my_func(
{{ source_table[0] }},
{{ provider_join_col }},
{{ my_table[0] }},
{{ consumer_join_col }},
{{ dimensions | sqlsafe }},
{{ filter_clause }}
) AS train_result;
$$
일반적인 다단계 흐름 패턴¶
Snowpark API 예제 에서는 데이터를 처리하고 중간 테이블을 생성한 다음 하나의 템플릿 호출로 결과 테이블을 생성한 다음 두 번째 템플릿 호출을 통해 결과를 직접 노출합니다.
Snowpark Container Services 예제 에서는 하나의 템플릿 호출로 학습 데이터를 생성하고 내부 테이블에 학습 데이터를 저장합니다. 두 번째 템플릿은 저장된 학습 데이터와 비교하여 사용자 입력을 분석합니다.