Projeto de fluxos de várias etapas¶
Visão geral¶
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.
As clean rooms têm vários mecanismos para permitir esses cenários avançados:
Cadeias de modelos: um uma cadeia de modelos executa um conjunto de modelos em uma ordem específica, usando a saída de cada modelo como a entrada do próximo modelo. A entrada para o primeiro modelo na cadeia é fornecida pelo usuário; a saída do último modelo na cadeia é retornada ao usuário.
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.
Funções internas personalizadas: você pode definir funções personalizadas em uma sala limpa, que podem ser chamadas por modelos nessa sala limpa. As funções podem ser definidas em uma sala limpa carregando UDFs ou UDTFs Python na sala limpa, ou criando um serviço de contêiner em sua sala limpa que expõe os pontos de extremidade que implementam as funções. Somente modelos da sala limpa podem chamar essas funções.
Nota
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.
Tabelas internas de 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.
Aqui estão alguns exemplos de criação de uma tabela interna:
Um modelo JinjaSQL pode criar uma tabela interna, o que é feito em alguns tipos de ativação.
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;
$$);
A UDF pode criar uma tabela interna. Normalmente, isso é feito por meio da execução de SQL em Python.
# 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
Quando você gera uma tabela interna que deve ser acessada por modelo ou código, pode usar um nome de tabela constante ou nomear a tabela dinamicamente e retornar o nome da tabela para o usuário, que então passa o nome da tabela para a função de resultados.
Aqui está um exemplo de uma tabela nomeada dinamicamente usada para armazenar resultados. O usuário faz duas chamadas: uma para gerar os dados e obter o nome da tabela, e uma segunda para ver os resultados.
O modelo do provedor chama a UDF
reach_impression_regressionpara processar os dados (o prefixocleanroomindica que se trata de uma UDF). A UDF retorna o nome do prefixo da tabela interna para o modelo, que o retorna ao chamador.-- 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 ) );
Acionamento de funções personalizadas¶
As funções personalizadas podem ser chamadas por modelos ou por código (UDFs, UDTFs ou pontos de extremidade do servidor de contêiner) na clean room. As funções carregadas por qualquer colaborador podem ser acessadas por modelos ou códigos de qualquer outro colaborador.
As funções de clean room sempre devem ser chamadas com o escopo do namespace apropriado:
cleanroom.function_nameao chamar uma função UDF/UDTF personalizadaservice_functions.function_nameao chamar uma função exposta como uma função incorporada do Snowpark Container Service.
Veja a seguir exemplos de como chamar uma UDF personalizada e um ponto de extremidade do servidor de contêiner personalizado a partir de um modelo:
Os modelos usam o escopo cleanroom para acessar a UDF ou as UDTFs.
-- 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') }});
$$
);
Os modelos usam o escopo service_functions para acessar as funções do servidor de contêiner.
-- 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;
$$
Padrões comuns de fluxo em várias etapas¶
O exemplo da Snowpark API processa dados, gera tabelas intermediárias e uma tabela de resultados com uma chamada de modelo e, depois, expõe os resultados diretamente por meio de uma segunda chamada de modelo.
O exemplo do Snowpark Container Services cria dados de treinamento com uma chamada de modelo e armazena os dados de treinamento em uma tabela interna. Um segundo modelo analisa a entrada do usuário em relação aos dados de treinamento armazenados.