다단계 흐름 디자인하기¶
개요¶
대부분의 Clean Room 사용은 Clean Room의 하나 이상의 테이블에 대해 단일 SQL 쿼리를 실행하고 응답에 결과를 표시하는 방식으로 이루어집니다. 그러나 흐름을 여러 단계로 나누어 순차적으로 또는 임의의 순서로 실행할 수 있고, 데이터를 처리하거나 전처리하기 위해 Python 코드를 호출해야 하는 사용 사례가 많이 있을 수 있습니다. 예를 들어, 데이터 세트에 대해 데이터를 한 번 학습한 다음 다양한 입력 데이터에 대해 단독 또는 배치로 여러 번 실행하는 머신 러닝 흐름이 있습니다.
Clean Rooms에는 이러한 고급 시나리오를 가능하게 하는 몇 가지 메커니즘이 있습니다.
템플릿 체인: 템플릿 체인 은 각 템플릿의 출력을 다음 템플릿의 입력으로 사용하여 특정 순서로 템플릿 세트를 실행합니다. 체인의 첫 번째 템플릿에 대한 입력은 사용자가 제공하고, 체인의 마지막 템플릿의 출력은 사용자에게 반환됩니다.
내부 테이블: 템플릿 또는 사용자 지정 내부 함수로 Clean Room 내에서 테이블을 만들 수 있습니다. 이러한 테이블은 템플릿 또는 사용자 지정 업로드 코드에 액세스할 수 있다는 점에서 연결된 테이블처럼 작동합니다. 내부 테이블은 상태 또는 데이터를 유지하는 데 유용하며, 머신 러닝 예제에서는 학습 데이터를 내부 테이블에 저장하고 내부 함수에서 사용합니다. 이러한 테이블은 Clean Room 내부의 템플릿 또는 업로드된 코드에 의해서만 액세스할 수 있습니다. 중간 데이터를 내부 테이블에 저장하는 것이 템플릿을 사용하여 대규모 정보 블록을 Clean Room 안팎으로 전달하는 것보다 훨씬 더 효율적입니다.
사용자 지정 내부 함수: Clean Room 내에서 해당 Clean Room의 템플릿으로 호출할 수 있는 사용자 지정 함수를 정의할 수 있습니다. Python UDF 또는 UDTF 를 Clean Room에 업로드하거나, 함수를 구현하는 엔드포인트를 노출하는 컨테이너 서비스를 Clean Room에 생성하여 함수를 정의할 수 있습니다. 이러한 함수는 Clean Room 내에서 템플릿으로만 호출할 수 있습니다.
참고
모든 메커니즘의 통일된 원칙은 템플릿을 사용하여 테이블과 함수에 액세스하거나 실행한다는 것입니다. Clean Room 내부 테이블에 액세스하거나 사용자 지정 Clean Room 함수를 실행하거나 내부 Clean Room 엔드포인트에 직접 액세스할 수 없으며 템플릿을 통해서만 액세스할 수 있습니다.
내부 Clean Room 테이블¶
Clean Room 내부에서 SQL 또는 Python을 사용하여 중간 결과를 저장하거나 사용자 또는 내부 함수(예: 학습 데이터)를 위한 영구 저장소를 위해 테이블을 만들 수 있습니다. 이러한 테이블은 연결된 테이블과 동일하게 작동하지만 다음과 같은 주의 사항이 있습니다.
이러한 테이블은 Clean Room 템플릿 또는 UDF/UDTF 를 사용하여 생성되며 외부 테이블과 연결되지 않습니다.
이러한 테이블은
cleanroom
네임스페이스에 만들어야 합니다.수동으로 만든 내부 테이블을 만든 후 행 및 열 정책을 설정할 수 있습니다.
테이블 이름이 정적이 아니고 다른 템플릿이나 코드에서 테이블에 액세스해야 하는 경우 사용자에게 테이블 이름을 반환해야 사용자가 해당 테이블에 액세스해야 하는 다른 템플릿에 동적 테이블 이름을 전달할 수 있습니다.
다음은 내부 테이블을 만드는 몇 가지 예입니다.
JinjaSQL 템플릿은 내부 테이블을 만들 수 있는데, 이 작업은 활성화 의 일부 유형에서 수행됩니다.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
$cleanroom_name,
$template_name,
$$
BEGIN
CREATE OR REPLACE TABLE cleanroom.activation_data_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_regression
UDF 를 호출하여 데이터를 처리합니다(cleanroom
접두사는 이것이 UDF 임을 나타냄). UDF 는 내부 테이블 접두사 이름을 템플릿에 반환하고, 템플릿은 이를 호출자에게 반환합니다.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') }}); $$ );
Python UDF 는 테이블 이름 접미사 이름을 템플릿 호출자에게 반환합니다.
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 suffix: {suffix}'
공급자 템플릿은 전달된 테이블 이름 접미사를 받아들이고 해당 테이블의 내용을 표시합니다.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template( $cleanroom_name, 'prod_get_results', $$ SELECT * FROM cleanroom.results_{{ results_suffix | sqlsafe }}; $$ );
컨슈머가 템플릿을 호출하여 테이블 이름 접미사를 전달합니다.
CALL samooha_by_snowflake_local_db.consumer.run_analysis( $cleanroom_name, 'prod_get_results', [], [], object_construct( 'results_suffix', $result_suffix -- Table name suffix to identify the results table. ) );
사용자 지정 함수 트리거하기¶
사용자 지정 함수는 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 예제 에서는 하나의 템플릿 호출로 학습 데이터를 생성하고 내부 테이블에 학습 데이터를 저장합니다. 두 번째 템플릿은 저장된 학습 데이터와 비교하여 사용자 입력을 분석합니다.