Projeto de fluxos de várias etapas¶
Visão geral¶
A maior parte do uso de clean rooms envolve a execução de uma única consulta SQL em uma ou mais tabelas em uma clean room e a exibição dos resultados na resposta. No entanto, há muitos casos de uso em que você pode querer dividir o fluxo em várias etapas, que podem ser executadas sequencialmente ou em qualquer ordem, e podem envolver a chamada de código Python para processar (ou pré-processar) os dados. Os exemplos incluem um fluxo de aprendizado de máquina em que os dados são treinados uma vez em relação a um conjunto de dados e, em seguida, executados várias vezes em relação a dados de entrada variados, individualmente ou em lotes.
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.
Tabelas internas: seu modelo ou funções internas personalizadas podem criar tabelas dentro de uma clean room. Essas tabelas se comportam como tabelas vinculadas, pois são acessíveis a modelos ou códigos personalizados carregados. As tabelas internas são úteis para manter o estado ou os dados; no exemplo do aprendizado de máquina, os dados de treinamento seriam salvos em uma tabela interna e usados por funções internas. Essas tabelas só podem ser acessadas por modelos ou códigos carregados dentro da clean room. O armazenamento de dados intermediários em tabelas internas é muito mais eficiente do que passar grandes blocos de informações para dentro e fora da clean room usando modelos.
Funções internas personalizadas: você pode definir funções personalizadas em uma clean room, que podem ser chamadas por modelos nessa clean room. As funções podem ser definidas em uma clean room por meio do upload de UDFs Python ou UDTFs na clean room, ou por meio da criação de um servidor de contêiner em sua clean room que expõe pontos de extremidade que implementam funções. Essas funções só podem ser chamadas por modelos dentro da clean room.
Nota
Um princípio unificador de todos os mecanismos é que as tabelas e funções são acessadas ou executadas usando um modelo. Você não pode acessar uma tabela interna de clean room, executar uma função personalizada de clean room ou acessar um ponto de extremidade interno de clean room diretamente, somente por meio de um modelo.
Tabelas internas de clean room¶
É possível criar tabelas dentro de uma clean room usando SQL ou Python para armazenar resultados intermediários ou para armazenamento persistente para o usuário ou suas funções internas (pense em dados de treinamento). Essas tabelas se comportam da mesma forma que as tabelas vinculadas, com as seguintes observações:
Essas tabelas são criadas usando um modelo de clean room ou uma UDF/UDTF, e não têm link com tabelas externas.
Essas tabelas devem ser criadas no namespace
cleanroom
.Você pode definir políticas de linha e coluna em tabelas internas criadas manualmente depois de criá-las.
Se o nome da tabela não for estático e a tabela precisar ser acessada por outros modelos ou códigos, você deve retornar o nome da tabela ao usuário, para que ele possa passar o nome da tabela dinâmica para quaisquer outros modelos que precisem acessar essa tabela.
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.
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;
$$);
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_regression
para processar os dados (o prefixocleanroom
indica que se trata de uma UDF). A UDF retorna o nome do prefixo da tabela interna para o modelo, que o retorna ao chamador.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') }}); $$ );
A UDF Python retorna o nome do sufixo do nome da tabela ao chamador do modelo.
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}'
O modelo de provedor aceita um sufixo de nome de tabela passado e exibe o conteúdo dessa tabela.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template( $cleanroom_name, 'prod_get_results', $$ SELECT * FROM cleanroom.results_{{ results_suffix | sqlsafe }}; $$ );
O consumidor chama o modelo, passando o sufixo do nome da tabela.
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. ) );
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_name
ao chamar uma função UDF/UDTF personalizadaservice_functions.function_name
ao 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.