Création de modèles de clean room personnalisés

À propos des modèles de clean rooms

Les modèles Clean room sont rédigés en JinjaSQL. JinjaSQL est une extension de la langue de création de modèles Jinja qui génère une requête SQL en sortie. JinjaSQL prend en charge les instructions logiques et la résolution des variables au moment de l’exécution pour permettre à l’utilisateur de personnaliser la requête au moment de l’exécution. Les variables sont généralement utilisées dans un modèle pour permettre à l’utilisateur de spécifier les noms des tables, les colonnes des tables et les valeurs personnalisées à utiliser dans sa requête.

Snowflake fournit une sélection de modèles préconçus pour les cas d’utilisation courants. Ces modèles de stock ne peuvent être utilisés que dans l’application web. Toutefois, les fournisseurs et les consommateurs peuvent créer des modèles personnalisés de clean room. Les modèles personnalisés ne peuvent être créés que dans le code, mais peuvent être exécutés soit dans le code, soit par l’intermédiaire de l’application web.

Il existe deux types généraux de modèles :

  • Modèles d’analyse, qui évaluent une instruction SELECT (ou un ensemble d’opérations SELECT).

  • Modèles d’activation, qui évaluent une instruction SELECT imbriquée dans une instruction CREATE TABLE et renvoient le nom de la table. Ce modèle génère des données qui sont exportées vers le compte Snowflake du consommateur ou du fournisseur ou vers un tiers, en fonction de la configuration de la clean room. Un modèle d’activation est très similaire à un modèle d’analyse avec quelques exigences supplémentaires.

Dans les UI de clean rooms, un modèle d’analyse peut être associé à un modèle d’activation pour permettre à l’appelant d’effectuer une analyse, puis d’envoyer des données à lui-même ou à un tiers. Le modèle d’activation ne doit pas nécessairement se résoudre à la même requête que le modèle d’analyse associé.

Création et exécution d’un modèle personnalisé

Dans une clean room avec paramètres par défaut, le fournisseur ajoute un modèle à une clean room et le consommateur peut le choisir, le configurer et l’exécuter :

  1. Le fournisseur conçoit un modèle personnalisé et l’ajoute à une clean room en appelant provider.add_custom_sql_template.

  2. Le consommateur appelle consumer.run_analysis pour exécuter le modèle du fournisseur, en lui transmettant les valeurs de toutes les variables nécessaires au modèle.

Ce flux ne nécessite pas d’autorisations de la part de l’autre partie, si ce n’est que le consommateur doit être invité dans une clean room par le fournisseur. Il existe des variantes de ce processus, telles que les modèles fournis par les consommateurs et les modèles gérés par les fournisseurs, qui sont couverts par.

Protection des données

Les modèles ne peuvent accéder qu’aux ensembles de données liés à la clean room par le fournisseur et le consommateur.

Le fournisseur et le consommateur ont tous deux la possibilité de définir des politiques de jointure, de colonne et d’activation sur leurs données afin de protéger les colonnes qui peuvent faire l’objet d’une jointure, d’une projection ou d’une projection dans les résultats activés.

Un exemple rapide

Voici un exemple simple de SQL qui joint une table de fournisseurs et une table de consommateurs par courriel et affiche le nombre de chevauchements par ville :

SELECT COUNT(*), city FROM consumer_table
  INNER JOIN provider_table
  ON consumer_table.hashed_email = provider_table.hashed_email
  GROUP BY city;
Copy

Voici à quoi ressemblerait cette requête sous la forme d’un modèle permettant à l’appelant de choisir les colonnes de sélection/groupe et de jointure ainsi que les tables :

SELECT COUNT(*), IDENTIFIER({{ group_by_col | column_policy }})
  FROM IDENTIFIER({{ my_table[0] }}) AS C
  INNER JOIN IDENTIFIER({{ source_table[0] }}) AS P
  ON IDENTIFIER({{ consumer_join_col | join_policy }}) = IDENTIFIER({{ provider_join_col | join_policy }})
  GROUP BY IDENTIFIER({{ group_by_col | column_policy }});
Copy

Notes sur le modèle :

  • Les valeurs contenues dans {{ double bracket pairs }} sont des variables personnalisées. group_by_col les valeurs de my_table, source_table, consumer_join_col, provider_join_col et group_by_col sont toutes des variables personnalisées renseignées par l’appelant.

  • source_table et my_table sont des variables de type tableau de chaînes définies par Snowflake et renseignées par l’appelant. Les membres du tableau sont les noms pleinement qualifiés des tables de fournisseurs et de consommateurs liées à la clean room. L’appelant spécifie les tables à inclure dans chaque tableau.

  • Les tables de fournisseurs doivent être appelées P et les tables de consommateurs C dans un modèle. Si vous avez plusieurs tables, vous pouvez les indexer comme suit : P1, P2, C1, C2, etc.

  • IDENTIFIER est nécessaire pour tous les noms de colonnes et de tables, car les variables dans {{ double brackets }} évaluent des chaînes littérales, qui ne sont pas des identificateurs valides.

  • les filtres JinjaSQL peuvent être appliqués aux variables. Snowflake implémente les filtres personnalisés join_policy et column_policy, qui vérifient si une colonne est conforme aux politiques de jointure ou de colonne dans la clean room, respectivement, et qui font échouer la requête si ce n’est pas le cas. Un filtre est appliqué au nom d’une colonne comme {{ column_name | filter_name }}.

Tous ces points seront examinés en détail ultérieurement.

Voici comment un consommateur pourrait exécuter ce modèle dans le code. Notez que les noms de colonnes sont qualifiés par les alias de table déclarés dans le modèle.

CALL SAMOOHA_BY_SNOWFLAKE_LOCAL_DB.CONSUMER.RUN_ANALYSIS(
  $cleanroom_name,
  $template_name,
  ['my_db.my_sch.consumer_table],       -- Populates the my_table variable
  ['my_db.my_sch.provider_table'],      -- Populates the source_table variable
  OBJECT_CONSTRUCT(                     -- Populates custom named variables
    'consumer_join_col','c.age_band',
    'provider_join_col','p.age_band',
    'group_by_col','p.device_type'
  )
);
Copy

Pour utiliser ce modèle dans l’application web, le fournisseur doit créer une forme UI personnalisée pour le modèle. La forme UI comporte des éléments de forme nommés qui correspondent aux noms des variables du modèle, et les valeurs fournies dans le formulaire sont transmises au modèle.

Astuce

Au début du développement, vous pouvez utiliser la procédure consumer.get_sql_jinja pour voir à quoi ressemblera votre modèle lorsqu’il sera rendu. Sachez toutefois que cette procédure ne prend pas en charge les extensions de filtre de clean room, telles que join_policy, et que vous devrez donc omettre ces filtres dans tout modèle envoyé à cette procédure.

Syntaxe des modèles personnalisés

Snowflake Data Clean Rooms prend en charge la version 3 du site JinjaSQL, avec quelques extensions comme indiqué.

Cette section comprend les rubriques suivantes :

Règles de dénomination des modèles

Lors de la création d’un modèle, les noms doivent être composés de lettres minuscules, de chiffres, d’espaces ou de traits de soulignement. Les modèles d’activation (à l’exception de l’activation du fournisseur gérée par le consommateur) doivent avoir un nom commençant par « activation ». Les noms de modèles sont attribués lorsque vous appelez provider.add_custom_sql_template ou consumer.create_template_request.

Exemples de noms valides :

  • my_template

  • activation_template_1

Exemple de noms non valides :

  • my template - Espaces non autorisés

  • My_Template - Seuls les modèles en minuscules sont autorisés

Variables de modèles

Les appelants d’un modèle peuvent transmettre des valeurs aux variables du modèle. La syntaxe JinjaSQL permet la liaison de variables pour n’importe quel nom de variable dans {{ double_brackets }}, mais Snowflake réserve quelques noms de variables que vous ne devez pas remplacer, comme décrit ci-dessous.

Prudence

Toutes les variables, qu’elles soient définies par Snowflake ou personnalisées, sont renseignées par l’utilisateur et doivent être traitées avec la prudence qui s’impose. Les modèles de Snowflake Data Clean Rooms doivent se résoudre en une seule instruction SELECT, mais vous devez toujours vous rappeler que toutes les variables sont transmises par l’appelant.

Variables définies par Snowflake

Tous les modèles de clean room ont accès aux variables globales suivantes, définies par Snowflake, mais transmises par l’appelant :

source_table:

Un tableau de chaînes de caractères indexé à partir de zéro, listant les tables et vues liées au fournisseur dans la clean room, utilisables par le modèle. Les noms de tables sont entièrement qualifiés, par exemple : my_db.my_sch.provider_customers

Exemple : SELECT col1 FROM IDENTIFIER({{ source_table[0] }}) AS p;

my_table:

Tableau (string) basé sur zéro des tables et vues consommateurs de la clean room qui peuvent être utilisées par le modèle. Les noms de tables sont entièrement qualifiés, par exemple : my_db.my_sch.consumer_customers

Exemple : SELECT col1 FROM IDENTIFIER({{ my_table[0] }}) AS c;

privacy:

Un ensemble de valeurs relatives à la vie privée associées aux utilisateurs et aux modèles. Voir la liste des champs enfants disponibles. Ces valeurs peuvent être définies explicitement pour l’utilisateur, mais votre modèle doit toujours fournir une valeur par défaut au cas où elles ne seraient pas paramétrées. Accédez aux champs enfants directement dans votre modèle, par exemple privacy.threshold.

Exemple : Voici un exemple de modèle qui utilise threshold_value pour imposer une taille de groupe minimale dans une clause d’agrégation.

SELECT
  IFF(a.overlap > ( {{ privacy.threshold_value | default(2)  | sqlsafe }} ),
                    a.overlap,1 ) AS overlap,
  c.total_count AS total_count
  ...
Copy

Note

Il existe deux variables globales pour les clean rooms : measure_columns et dimensions. Leur utilisation n’est plus recommandée, mais ils sont encore définis et apparaissent dans certains modèles et documentations. Vous ne devez donc pas aliaser des tables ou des colonnes en utilisant l’un ou l’autre de ces noms afin d’éviter les collisions de noms.

Variables personnalisées

Les créateurs de modèles peuvent inclure des variables arbitraires dans un modèle qui peuvent être remplies par l’appelant. Ces variables peuvent porter n’importe quel nom arbitraire conforme à Jinja, à l’exception des variables définies par Snowflake ou des noms d’alias de table. Si vous voulez que votre modèle soit utilisable dans l’application web, vous devez également fournir une forme UI pour les utilisateurs de l’application web. Pour les utilisateurs de l’API, vous devez fournir une bonne documentation sur les variables obligatoires et facultatives.

Les variables personnalisées sont accessibles par votre modèle, comme indiqué ici pour la variable personnalisée max_income:

SELECT income FROM my_db.my_sch.customers WHERE income < {{ max_income }};
Copy

Les utilisateurs peuvent transmettre des variables à un modèle de deux manières différentes :

  • Dans l’application web, en sélectionnant ou en fournissant des valeurs par le biais d’une forme UI créée par le développeur du modèle. Cette forme UI contient des éléments de forme où l’utilisateur peut fournir des valeurs pour votre modèle. Le nom de l’élément de la forme est le nom de la variable. Le modèle utilise simplement le nom de l’élément de la forme pour accéder à la valeur. Créez la forme UI à l’aide de provider.add_ui_form_customizations.

  • Dans le code, un consommateur appelle consumer.run_analysis et transmet les noms des tables sous forme de tableaux d’arguments et les variables personnalisées sous forme de paires nom-valeur dans l’argument analysis_arguments.

Note

Si vous devez accéder à des valeurs fournies par l’utilisateur dans un code Python personnalisé téléchargé dans la clean room, vous devez transmettre explicitement les valeurs des variables au code par le biais d’arguments de fonctions Python ; les variables de modèle ne sont pas directement accessibles dans le code Python à l’aide de {{jinja variable binding syntax}}.

Résoudre correctement les variables

Les valeurs de chaîne passées dans le modèle se traduisent par une chaîne littérale dans le modèle final. Cela peut provoquer des erreurs d’analyse SQL ou des erreurs logiques si vous ne gérez pas les variables de liaison de manière appropriée :

  • SELECT {{ my_col }} FROM P; se résout en SELECT 'my_col' from P; qui renvoie simplement la chaîne « my_col » - ce qui n’est probablement pas ce que vous voulez.

  • SELECT age FROM {{ my_table[0] }} AS P; se résout en SELECT age FROM 'somedb.somesch.my_table' AS P;, ce qui provoque une erreur d’analyse car une table doit être un identificateur et non une chaîne littérale.

  • SELECT age FROM IDENTIFIER({{ my_table[0] }}) AS P {{ where_clause }}; en passant par « WHERE age < 50 » donne SELECT age FROM mytable AS P 'WHERE age < 50' ;, ce qui est une erreur d’analyse à cause de la clause de la chaîne littérale WHERE.

Par conséquent, le cas échéant, vous devez résoudre les variables. Voici comment résoudre correctement les variables dans votre modèle :

Noms des tables et des colonnes

Les variables qui spécifient des noms de tables ou de colonnes doivent être converties en identificateurs dans votre modèle de l’une des deux manières suivantes :

  • IDENTIFIER: Par exemple : SELECT IDENTIFIER({{ my_column }}) FROM P ;

  • sqlsafe: Ce filtre JinjaSQL résout les chaînes d’identificateurs en texte SQL. Une instruction équivalente au point précédent est SELECT {{ my_column | sqlsafe }} FROM P ;

Votre utilisation particulière dicte quand utiliser IDENTIFIER ou sqlsafe. Par exemple, c.{{ my_column | sqlsafe }} ne peut pas être facilement réécrit en utilisant IDENTIFIER.

Instruction SQL dynamique

Lorsque vous avez une variable chaîne qui doit être utilisée comme littéral SQL, telle qu’une clause WHERE, utilisez le filtre sqlsafe dans votre modèle. Par exemple :

SELECT age FROM IDENTIFIER({{ my_table[0] }}) AS C WHERE {{ where_clause }};
Copy

Si un utilisateur introduit « age < 50 » dans where_clause, la requête aboutira à SELECT age FROM sometable AS C WHERE 'age < 50';, qui n’est pas valide SQL en raison de la condition relative à la chaîne littérale WHERE. Dans ce casse-tête, vous devez utiliser le filtre sqlsafe:

SELECT age FROM IDENTIFIER( {{ my_table[0] }} ) as C {{ where_clause | sqlsafe }};
Copy

Alias de table requis

Au niveau supérieur de votre requête, toutes les tables ou sous-requêtes doivent être appelées P (pour les tables de fournisseurs) ou C (pour les tables de consommateurs) afin que Snowflake valide correctement les politiques de jointure et de colonne dans la requête. Toute colonne qui doit être vérifiée par rapport aux politiques de jointure ou de colonne appartient à une table dont l’alias est P ou C. (La spécification de P ou C indique au back-end s’il doit valider une colonne par rapport à la politique du fournisseur ou du consommateur, respectivement)

Si vous utilisez plusieurs tables de fournisseurs ou de consommateurs dans votre requête, ajoutez un suffixe numérique séquentiel basé sur 1 à chaque alias de table après le premier. Ainsi : P, P1, P2, et ainsi de suite pour les première, deuxième et troisième tables de fournisseurs, et C, C1, C2, et ainsi de suite pour les première, deuxième et troisième tables de consommateurs. L’index P ou C doit être séquentiel et sans trous (c’est-à-dire que vous devez créer les alias P, P1, et P2, et non P, P2, et P4).

Exemple

SELECT col1 FROM IDENTIFIER({{ source_table[0] }}) AS P;
Copy

Filtres Template]

Snowflake prend en charge tous les filtres standard Jinja et la plupart des filtres JinjaSQL standard, ainsi que quelques extensions :

  • join_policy: Vérifie si la colonne est autorisée par la politique de jointure de la table et échoue si ce n’est pas le cas.

  • column_policy: Vérifie si la colonne est autorisée par la politique de colonne du modèle (est autorisée à être projetée).

  • activation_policy: Vérifie si la colonne filtrée est autorisée par les politiques d’activation de la clean room (provider.set_activation_policy ou consumer.set_activation_policy).

  • join_and_column_policy: Vérifie si la colonne est autorisée par les politiques de jointure, d’activation ou de colonne. Utilisé pour offrir plus de flexibilité dans la clean room, pour permettre aux collaborateurs de mettre à jour les politiques de jointure et de colonne sans modifier le modèle.

  • Le filtre identifier JinjaSQL n’est pas supporté par les modèles Snowflake.

Les filtres JinjaSQL sont analysés de gauche à droite :

  • {{ my_col | column_policy }} Correct

  • {{ my_col | sqlsafe | column_policy }} Correct

  • {{ column_policy | my_col }} Incorrect

  • {{ my_col | column_policy | sqlsafe }} Incorrect

Appliquer les politiques des clean rooms

Clean rooms ne vérifie pas automatiquement les politiques de clean rooms par rapport aux colonnes utilisées dans un modèle. Si vous souhaitez appliquer une politique à une colonne, vous devez appliquer le filtre de politique <label-dcr_template_filters> approprié à cette colonne dans le modèle. Par exemple :

JOIN IDENTIFIER({{ source_table[0] }}) AS p
  ON {{ c_join_col | sqlsafe | join_policy }} = {{ p_join_col | sqlsafe }}
Copy

Cela permet de tester la politique de jonction par rapport à la colonne transmise à c_join_col, mais pas par rapport à p_join_col.

Notez que les noms de colonnes ne peuvent pas être ambigus lors des tests de politiques, comme pour toute autre utilisation de SQL. Ainsi, si vous avez des colonnes portant le même nom dans deux tables, vous devez qualifier le nom de la colonne afin de tester la politique par rapport à cette colonne.

Exécution de code Python personnalisé

Les modèles peuvent exécuter le code Python téléchargé dans la clean room. Le modèle peut appeler une fonction Python qui accepte les valeurs d’une ligne de données et renvoie des valeurs à utiliser ou à projeter dans la requête.

  • Lorsqu’un fournisseur télécharge un code Python personnalisé dans une clean room, le modèle appelle des fonctions Python avec la syntaxe cleanroom.function_name. Plus de détails ici.

  • Lorsqu’un consommateur télécharge un code Python personnalisé dans une clean room, le modèle appelle la fonction avec la valeur nom_de_fonction nue transmise à consumer.generate_python_request_template (non champ d’application de la clean room `` comme l’est le code du fournisseur). Plus de détails ici.

Exemple de code fournisseur :

-- Provider uploads a Python function that takes two numbers and returns the sum.
call samooha_by_snowflake_local_db.provider.load_python_into_cleanroom(
  $cleanroom_name,
  'simple_addition',                        -- Function name to use in the template
  ['someval integer', 'added_val integer'], -- Arguments
  [],                                       -- No packages needed
  'integer',                                -- Return type
  'main',                                   -- Handler for function name
  $$

def main(input, added_val):
  return input + int(added_val)
    $$
);

-- Template passes value from each row to the function, along with a
-- caller-supplied argument named 'increment'
call samooha_by_snowflake_local_db.provider.add_custom_sql_template(
    $cleanroom_name,
    'simple_python_example',
$$
    SELECT val, cleanroom.simple_addition(val, {{ increment | sqlsafe }})
    FROM VALUES (5),(8),(12),(39) AS P(val);
$$
);
Copy

Remarques relatives à la sécurité

Un modèle doit être évalué en une seule requête SELECT, qui est exécutée par l’application native de la clean room. Le modèle n’est pas exécuté avec l’identité de l’utilisateur actuel.

L’utilisateur n’a pas d’accès direct aux données de la clean room ; tout l’accès se fait par l’application native via les résultats du modèle.

Appliquez un filtre de politique chaque fois qu’une colonne est utilisée dans votre requête, même lorsque vous définissez un nom de colonne explicitement dans le modèle, ou lorsque la colonne ou la table est fournie par vous. Vous pouvez modifier vos politiques de jointure ou de colonne ultérieurement, ou changer la colonne, et oublier de mettre à jour le modèle. Pour toutes les colonnes fournies par l’utilisateur, vous devez appliquer un filtre join_policy, column_policy, join_and_column_policy, ou activation_policy.

Modèles d’activation

Un modèle peut également être utilisé pour enregistrer les résultats de la requête dans une table située à l’extérieur de la clean room ; il s’agit de l’activation. Actuellement, les seules formes d’activation supportées pour les modèles personnalisés sont l’activation du fournisseur et l’activation du consommateur (stockage des résultats sur le compte Snowflake du fournisseur ou du consommateur, respectivement). Découvrez comment mettre en œuvre l’activation.

Un modèle d’activation est un modèle d’analyse auquel s’ajoutent les exigences suivantes :

  • Les modèles d’activation sont des instructions JinjaSQL qui évaluent un bloc de script SQL, contrairement aux modèles d’analyse, qui peuvent être de simples instructions SELECT.

  • Le nom du modèle d’activation doit commencer par la chaîne activation (sauf pour les modèles d’activation des fournisseurs gérés par les consommateurs). Par exemple : activation_my_template.

  • Le modèle d’activation doit créer une table dont le nom dépend du type d’activation qu’il permet :

    • Activation du fournisseur gérée par le fournisseur : Le nom de la table générée doit être cleanroom.temp_result_data.

    • Tous les autres types d’activité : Le nom de la table générée doit être préfixé par cleanroom.activation_data_, par exemple : cleanroom.activation_data_cross_activation_results. Le nom de la table doit être unique au sein de votre clean room.

    Cette table générée est une table intermédiaire ; vous ne devez pas essayer d’y accéder directement.

  • Le bloc de script doit se terminer par une instruction RETURN qui renvoie le nom de la table générée, sans le préfixe cleanroom. ou cleanroom.activation_data_.

  • Toute colonne activée doit être listée dans la politique d’activation du fournisseur ou du consommateur qui a lié les données, et le filtre activation_policy doit lui être appliqué. Notez qu’une colonne peut être à la fois une colonne d’activation et une colonne de jointure.

  • Si le modèle doit être exécuté à partir des UI de clean rooms, vous devez fournir une forme web qui comprend les champs activation_template_name et enabled_activations. Les modèles à utiliser dans l’UI doivent avoir un modèle d’analyse et un modèle d’activation associé.

  • Toutes les colonnes calculées doivent être explicitement aliasées, plutôt que d’avoir des noms déduits, parce qu’une table est générée. C’est-à-dire :

    SELECT COUNT(*), P.status from T AS P; FAILS car le nom de la colonne COUNT est déduit.

    SELECT COUNT(*) AS COUNT_OF_ITEMS, P.status from T AS P; SUCCEEDS parce qu’elle crée explicitement un alias pour la colonne COUNT.

Voici deux échantillons de modèles d’activation de base. L’une concerne l’activation du serveur géré par le fournisseur, l’autre les autres types d’activation. Elles se distinguent par les deux lignes surlignées, qui contiennent le nom de la table de résultats.

-- These are the required table name strings.
BEGIN
  CREATE OR REPLACE TABLE cleanroom.temp_result_data AS
    SELECT COUNT(c.status) 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 'temp_result_data';
END;
Copy

Prochaines étapes

Une fois que vous aurez maîtrisé le système de création de modèles, lisez les détails relatifs à la mise en place d’une clean room avec votre type de modèle :

  • Les modèles du fournisseur sont des modèles rédigés par le fournisseur. Il s’agit du cas d’utilisation par défaut.

  • Les modèles du consommateur sont des modèles rédigés par le consommateur. Dans certains cas, le créateur d’une clean room souhaite permettre au consommateur de créer, de télécharger et d’exécuter ses propres modèles dans la clean room.

  • Les modèles d’activation créent une table de résultats après une exécution réussie. En fonction du modèle d’activation, la table des résultats peut être soit enregistrée sur le compte du fournisseur ou du consommateur en dehors de la clean room, soit envoyée à un fournisseur d’activation tiers répertorié dans le hub d’activation.

  • Les modèles enchaînés vous permettent d’enchaîner plusieurs modèles où la sortie de chaque modèle est utilisée par le modèle suivant dans la chaîne.

Plus d’informations