Charger et exécuter des fonctions personnalisées dans une salle blanche¶
Vue d’ensemble¶
Vous pouvez charger des UDFs et des UDTFs Python personnalisées dans votre salle blanche et les exécuter à partir de vos modèles pour effectuer des actions de données complexes. Ces actions comprennent le machine learning ou la manipulation personnalisée des données dans une requête, dans le cadre d’une seule étape ou d’un flux à plusieurs étapes. Python est le seul langage de codage pris en charge pour les UDFs personnalisées.
Votre code importé peut importer et utiliser des paquets à partir d’un bundle de packages Python approuvés et l’APISnowpark.
Les fournisseurs et les consommateurs peuvent charger du code Python personnalisé dans une salle blanche, bien que le processus soit différent pour les fournisseurs et les consommateurs. Chaque bundle de code importé peut définir plusieurs fonctions qui s’appellent entre elles, mais un bundle n’expose qu’une seule fonction de gestionnaire. Cette fonction de gestionnaire peut être appelée par des modèles créés ou exécutés par quiconque utilise la salle blanche. Si le code crée des tables internes, ces tables sont accessibles comme décrit dans la section Conception de flux à plusieurs étapes.
Le code importé ne peut pas être supprimé, mais il peut être mis à jour.
Cette page vous montre comment charger et exécuter des UDFs et des UDTFs Python personnalisées en tant que fournisseur ou consommateur.
Astuce
Pour obtenir des informations générales sur la manière de développer vos propres UDFs Python dans une salle blanche, consultez les rubriques suivantes :
Fonctionnement des UDFs sur Snowflake pour des informations générales sur la manière de créer des fonctions Python dans Snowflake.
Création de UDTFs dans Snowflake si vous souhaitez renvoyer des tables à partir de vos fonctions.
Création et chargement des modèles personnalisés dans une salle blanche. Les UDFs/UDTFs sont appelées à partir d’un modèle personnalisé.
Utilisation de Snowpark dans les salles blanches (si vous souhaitez appeler vos UDFs à partir de Snowpark).
Mise à jour des fonctions personnalisées¶
Vous pouvez charger ou remplacer une fonction existante que vous avez chargée, mais vous ne pouvez pas supprimer une fonction existante.
Le chargement d’une fonction avec exactement la même signature que celle que vous avez chargée précédemment remplacera la fonction existante. La signature est le nom de la fonction insensible à la casse du gestionnaire externe, et les types de données de tous les paramètres, dans le même ordre. Les noms des paramètres n’ont pas d’importance. Vous ne pouvez pas remplacer une fonction téléchargée par un autre compte.
Comme la signature doit correspondre lorsque vous mettez à jour une fonction, vous ne pouvez pas modifier la signature d’une fonction existante : si vous chargez la fonction foo(name VARIANT age INTEGER)
, puis chargez la fonction foo(name VARIANT age FLOAT)
, la deuxième fonction sera ajoutée à la salle blanche en plus de la première, car les types d’arguments diffèrent.
Code soumis par le fournisseur¶
Les fonctions soumises par le fournisseur peuvent être chargées sous forme de code en ligne ou à partir d’une zone de préparation Snowflake. Les deux techniques sont couvertes ici.
Votre code chargé peut importer et utiliser nativement des packages à partir d’un ensemble approuvé de packages Python. Si vous avez besoin d’un package non proposé par défaut, vous devez utiliser Snowpark Container Services dans une salle blanche pour héberger votre code.
Vous ne pouvez pas voir le code importé, ni même votre propre code, alors veillez à inclure une copie de ce que vous chargez exactement dans une salle blanche.
Astuce
Après avoir mis à jour le code écrit par le fournisseur, vous devez mettre à jour la directive de version par défaut, puis appeler provider.create_or_update_cleanroom_listing
pour propager les changements aux consommateurs. Si vous n’appelez pas provider.create_or_update_cleanroom_listing
, votre version par défaut ne sera pas mise à jour pour les consommateurs qui utilisent actuellement la salle blanche.
Voici une vue de haut niveau de la manière dont un fournisseur ajoute du code à une salle blanche :
Le fournisseur crée et configure la salle blanche de manière habituelle.
Le fournisseur charge le code en appelant
provider.load_python_into_cleanroom
. Vous pouvez charger votre code en ligne directement dans cette procédure ou charger un fichier de code dans une zone de préparation. Puis, indiquez l’emplacement de la zone de préparation dans cette procédure.Bien que votre code puisse inclure plusieurs fonctions, un seul gestionnaire est exposé pour chaque chargement. Pour exposer plusieurs fonctions pour les modèles, téléchargez chaque gestionnaire en appelant
provider.load_python_into_cleanroom
.Après chaque chargement de code réussi, une nouvelle version corrective de la salle blanche est générée. Vous devez ensuite améliorer la version par défaut en appelant
provider.set_default_release_directive
avec le nouveau numéro de correctif. Si la salle blanche est exposée à l’extérieur, les contrôles de sécurité sont exécutés avant d’installer votre code et vous devez appelerprovider.view_cleanroom_scan_status
pour confirmer que les contrôles de sécurité ont réussi avant d’incrémenter la version par défaut.Vous créez et chargez un modèle personnalisé qui appelle votre code. Le modèle appelle la fonction de gestionnaire à l’aide du champ d’application de
cleanroom
, qui est :cleanroom.my_function
. Par exemple, un modèle qui appelle une fonctionsimple_add
personnalisée que vous avez chargée pourrait ressembler à ceci :SELECT cleanroom.simple_add(1, 2), cleanroom.simple_add({{ price | sqlsafe | int }}, {{ tax | sqlsafe | int }})
Le consommateur exécute votre modèle de la même manière que tout autre modèle.
Astuce
Si le consommateur rencontre une erreur de montage lorsqu’il installe une salle blanche avec du code personnalisé, cela peut indiquer une erreur de syntaxe dans le code.
Vous trouverez des exemples de code démontrant ce flux dans la section d’exemple de code écrit par le fournisseur.
Notes importantes sur la gestion des versions¶
Chaque fois que le fournisseur charge une fonction, le nombre de correctifs augmente (avec une limite de 99 numéros de correctifs). Par conséquent, faites de votre mieux pour tester et déboguer rigoureusement votre code avant de l’ajouter à la salle blanche afin de réduire les mises à jour de versions au cours du développement.
Si vous mettez à jour un numéro de correctif, les clients qui utilisent l’UI des salles blanches peuvent devoir actualiser la page pour voir le changement. Les clients qui utilisent l’API devrait voir les changements immédiatement, mais cela peut prendre un certain temps en fonction des ressources disponibles. En savoir plus sur la gestion des versions des salles blanches.
Charger des fonctions en ligne écrites par le fournisseur¶
Vous pouvez charger le code en ligne dans le paramètre code
de provider.load_python_into_cleanroom
. Voici un exemple de chargement d’une fonction simple en ligne :
CALL samooha_by_snowflake_local_db.provider.load_python_into_cleanroom(
$cleanroom_name,
'simple_add', -- Name used to call the UDF from a template.
['first INTEGER', 'second INTEGER'], -- Arguments of the UDF, specified as '<variable_name> <SQL type>' pairs.
['numpy', 'pandas'], -- Packages imported by the UDF.
'INTEGER', -- SQL return type of UDF.
'add_two', -- Handler function in your code called when external name is called.
$$
import numpy as np # Not used, but you can load supported packages.
import pandas as pd
def add_two(first, second):
return first + second
$$
);
Le modèle d’appel appelle cleanroom.simple_add
pour appeler cette fonction. Les exemples de fonctions écrites par le fournisseur montrent comment charger du code en ligne.
Chargement de fonctions écrites par un fournisseur à partir d’une zone de préparation¶
Vous pouvez charger des fichiers Python dans une zone de préparation de salle blanche et faire référence à la zone de préparation lorsque vous appelez provider.load_python_into_cleanroom
. Le chargement de code à partir d’une zone de préparation vous permet de développer le code de votre système local dans un éditeur, d’éviter les erreurs copier/coller lorsque vous le chargez en ligne et d’avoir un meilleur contrôle des versions. Notez que vous pouvez charger plusieurs fichiers dans un seul appel de procédure, mais qu’une seule fonction de gestionnaire est exposée pour chaque chargement.
Le code est chargé depuis une zone de préparation dans la salle blanche lorsque vous appelez load_python_into_cleanroom
. Les modifications ultérieures apportées au code sur la zone de préparation ne sont pas répercutées dans la salle blanche.
Pour charger votre UDF dans une zone de préparation :
Créez votre fichier .py et rendez-le disponible dans un emplacement où vous pouvez le charger dans une zone de préparation Snowsight.
Pour obtenir le nom de la zone de préparation de votre salle blanche, appelez
provider.get_stage_for_python_files($cleanroom_name)
. Cette zone de préparation est accessible par la salle blanche. Vous ne pouvez pas utiliser une zone de préparation arbitraire que vous créez.Chargez le fichier .py dans la zone de préparation de votre salle blanche. Il y a plusieurs façons de procéder, notamment en utilisant la CLI, Snowsight ou des pilotes spécifiques à la langue.
Appelez
provider.load_python_into_cleanroom
avec l’emplacement de la zone de préparation, le gestionnaire, le nom externe, les arguments et le type de retour. Les modèles de votre salle blanche peuvent désormais appeler la fonction.
L’exemple de code suivant montre comment charger du code dans une salle blanche à partir d’une zone de préparation.
-- Save the following code as reverser.py:
--import numpy as np
--def main(some_string):
-- '''Return the reverse of a string plus a random number 1-10'''
-- return some_string[::-1] + str(np.random.randint(1,10))
-- Get the stage for your clean room.
CALL samooha_by_snowflake_local_db.provider.get_stage_for_python_files($cleanroom_name);
-- Save the file to the stage. Here is how to do it by using the Snowflake CLI
PUT file://~/reverser.py <STAGE_NAME> overwrite=True auto_compress=False;
-- Load the code from the stage into the clean room.
CALL samooha_by_snowflake_local_db.provider.load_python_into_cleanroom(
$cleanroom_name,
'reverse', -- Name used to call the function
['some_string STRING'], -- Arguments and SQL types
['numpy'], -- Any required packages
['/reverser.py'], -- Relative path to file on stage
'STRING', -- Return type
'reverser.main' -- <FILE_NAME>.<FUNCTION_NAME>
);
-- Uploading code, even from a stage, increases the patch number.
CALL samooha_by_snowflake_local_db.provider.set_default_release_directive(
$cleanroom_name, 'V1_0', <NEW_PATCH_NUMBER>);
-- Upload a template that calls the function.
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
$cleanroom_name,
$udf_template_name,
$$
SELECT
p.status,
cleanroom.reverse(p.status)
FROM SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS AS p
LIMIT 100;
$$
);
-- Switch to the consumer account and run the template to see the results.
Les exemples de code écrit par le fournisseur illustrent le chargement de code à partir d’une zone de préparation.
Exemples de code écrits par le fournisseur¶
Les exemples suivants illustrent l’ajout de UDFs et de UDTFs écrites par le fournisseur dans une salle blanche.
Téléchargez les exemples suivants, puis chargez-les sous forme de fichiers de feuilles de calcul dans votre compte Snowflake. Vous avez besoin de comptes distincts pour le fournisseur et le consommateur, chacun avec l’API de salles blanches installée. Remplacez les informations comme indiqué dans les fichiers d’exemple.
:download :
Exemple de code fournisseur</samples/clean-rooms/provider-udf-p.sql>
:download :
Exemple de code consommateur</samples/clean-rooms/provider-udf-c.sql>
:download :
Chargement d’un fichier à partir d’une zone de préparation </samples/clean-rooms/udf_from_stage.ipynb>
. Exécutez ce notebook après avoir exécuté l’exemple du fournisseur pour essayer de charger une UDF à partir d’une zone de préparation.
Code soumis par le consommateur¶
Un consommateur peut soumettre du code d’UDF ou d’UDTF et l’appelez à partir d’un modèle personnalisé. Le code téléchargé par le consommateur est regroupé dans une seule procédure avec un modèle personnalisé et téléchargé dans un seul appel de procédure. Le code du consommateur est lié directement à ce modèle et ne peut pas être appelé par d’autres modèles.
Pour charger du code en tant que consommateur, vous devez comprendre la syntaxe des modèles personnalisés et comment soumettre un modèle défini par le consommateur.
Notez que tout code chargé par un consommateur peut être vu par le fournisseur lorsqu’il demande l’autorisation de l’importer. Le code du consommateur est également visible chaque fois qu’un fournisseur ou un consommateur examine le modèle.
Voici un aperçu des étapes à suivre pour charger un code consommateur personnalisé :
Le fournisseur crée la salle blanche de la manière standard, puis invite le consommateur.
Le consommateur installe et configure la salle blanche de la manière standard.
Le consommateur prépare un modèle. Le modèle appelle l’UDF ou l’UDTF dans l’espace de noms
cleanroom
. Par exemple, pour appeler la fonctioncalculate_tax
définie par le consommateur, un modèle simple peut ressembler à l’extrait suivant :SELECT {{ cleanroom.calculate_tax(p.cost) }} AS Tax FROM my_db.my_sch.sales AS p;
Le consommateur prépare son code Python. Nous vous recommandons d’utiliser des guillemets doubles (
" "
) plutôt que des guillemets simples (' '
) dans votre code afin d’éviter tout échappement supplémentaire nécessaire ultérieurement. Votre code peut faire référence à un bundle de bibliothèques Python sélectionnées.Le consommateur transmet son code Python à
consumer.generate_python_request_template
. La procédure renvoie le code Python sous forme de procédure stockée, avec un espace réservé pour le modèle JinjaSQL personnalisé. Il existe plusieurs chaînes de plusieurs lignes dans le modèle qui utilisent$$
en tant que délimiteurs à plusieurs lignes.Remplacez l’espace réservé du modèle dans la sortie de
generate_python_request_template
par votre modèle JinjaSQL.Dans le modèle combiné, échappez les guillemets simples comme suit :
\'
. En effet, les guillemets simples seront utilisés comme délimiteurs externes pour toute la chaîne de procédure multiligne. Par exemple :BEGIN CREATE OR REPLACE FUNCTION CLEANROOM.custom_compare(min_status STRING, max_status STRING, this_status STRING) RETURNS boolean LANGUAGE PYTHON RUNTIME_VERSION = 3.10 PACKAGES = (\'numpy\') HANDLER = \'custom_compare\' AS $$ import numpy as np def custom_compare(min_status:str, max_status:str, this_status:str): statuses = [\'MEMBER\', \'SILVER\', \'GOLD\', \'PLATINUM\'] return ((statuses.index(this_status) >= statuses.index(min_status)) & (statuses.index(this_status) <= statuses.index(max_status))) $$; -- Custom template LET SQL_TEXT varchar := $$ SELECT c.status, c.hashed_email FROM IDENTIFIER( {{ my_table[0] }} ) as c WHERE cleanroom.custom_compare({{ min_status }}, {{ max_status }}, c.status); $$; LET RES resultset := (EXECUTE IMMEDIATE :SQL_TEXT); RETURN TABLE(RES); END;
Appelez
consumer.create_template_request
avec votre modèle combiné. Utilisez des guillemets simples (' '
) au lieu de délimiteurs à double signe de dollar ($$...$$
) autour du code que vous fournissez pour la procédure stockée dans l’argumenttemplate_definition
. Par exemple :CALL samooha_by_snowflake_local_db.consumer.create_template_request( $cleanroom_name, $template_name, ' BEGIN -- First, define the Python UDF. CREATE OR REPLACE FUNCTION CLEANROOM.custom_compare(min_status STRING, max_status STRING, this_status STRING) RETURNS boolean LANGUAGE PYTHON RUNTIME_VERSION = 3.10 PACKAGES = (\'numpy\') HANDLER = \'custom_compare\' AS $$ import numpy as np def custom_compare(min_status:str, max_status:str, this_status:str): statuses = [\'MEMBER\', \'SILVER\', \'GOLD\', \'PLATINUM\'] return ((statuses.index(this_status) >= statuses.index(min_status)) & (statuses.index(this_status) <= statuses.index(max_status))) $$; -- Then define and execute the SQL query. LET SQL_TEXT varchar := $$ SELECT c.status, c.hashed_email FROM IDENTIFIER( {{ my_table[0] }} ) as c WHERE cleanroom.custom_compare({{ min_status }}, {{ max_status }}, c.status); $$; -- Execute the query and then return the result. LET RES resultset := (EXECUTE IMMEDIATE :SQL_TEXT); RETURN TABLE(RES); END; ');
Le consommateur et le fournisseur poursuivent avec le flux de modèles défini par le consommateur :
Le fournisseur voit la requête de modèle (
provider.list_pending_template_requests
) et l’approuve ensuite en appelantapprove_template_request
. Dans la requête, le fournisseur peut voir le modèle et le code en bundle.Le consommateur vérifie le statut de la requête (
consumer.list_template_requests
), et lorsque le statut est APPROVED, il exécute le modèle (consumer.run_analysis
).
Exemples de code écrit par les consommateurs¶
Les exemples suivants illustrent l’ajout d’UDFs écrites par le fournisseur dans une salle blanche.
Téléchargez les exemples suivants, puis chargez-les sous forme de fichiers de feuilles de calcul dans votre compte Snowflake. Vous avez besoin de comptes distincts pour le fournisseur et le consommateur, chacun avec l’API de salles blanches installée. Remplacez les informations comme indiqué dans les fichiers d’exemple :
:download :
Exemple de code fournisseur</samples/clean-rooms/consumer-udf-p.sql>
:download :
Exemple de code consommateur</samples/clean-rooms/consumer-udf-c.sql>