- Executable UDFs lancent un programme externe ou un script (Python, Bash, etc.) et lui transmettent des blocs de données en flux via STDIN / STDOUT. Utilisez-les pour intégrer du code ou des outils existants sans recompiler ClickHouse. Leur surcoût par appel est plus élevé que celui des options exécutées dans le processus, et elles conviennent mieux à une logique plus lourde ou aux cas où un environnement d’exécution différent est nécessaire.
- SQL UDFs sont définies avec
CREATE FUNCTIONuniquement en SQL. Elles sont intégrées/dépliées dans le plan de requête (sans passer par un processus distinct), ce qui les rend légères et idéales pour réutiliser une logique d’expression ou simplifier des colonnes calculées complexes. - Experimental WebAssembly UDFs exécutent du code compilé en WebAssembly dans un sandbox au sein du processus serveur. Elles offrent un surcoût par appel plus faible que les exécutables externes, avec une meilleure isolation que les extensions natives, ce qui les rend adaptées aux algorithmes personnalisés écrits dans des langages pouvant cibler WASM (par ex. C/C++/Rust).
- Experimental UDF exécutable basé sur un driver permettent à un “driver” fourni par l’opérateur de transformer un extrait de code fourni dans
CREATE FUNCTION ... ENGINE = DriverName(...) AS '...'en une executable UDF au moment de la création de la fonction (par exemple, en le compilant). Elles s’appuient sur les executable UDFs et nécessitent une configuration du driver côté serveur.
Fonctions exécutables définies par l’utilisateur
Dans ClickHouse Cloud, les UDF exécutables sont en bêta publique et sont créées via l’interface de la Cloud Console. Consultez les fonctions définies par l’utilisateur dans Cloud pour la procédure propre à Cloud.
user_defined_executable_functions_config.
Une configuration de fonction contient les paramètres suivants :
La commande doit lire les arguments depuis
STDIN et écrire le résultat sur STDOUT. Elle doit traiter les arguments de manière itérative. Autrement dit, après avoir traité un fragment d’arguments, elle doit attendre le fragment suivant.
Fonctions exécutables définies par l’utilisateur
Exemples
UDF à partir d’un script intégré
test_function_sum en définissant execute_direct sur 0, à l’aide d’une configuration XML ou YAML.
- XML
- YAML
Fichier
test_function.xml (/etc/clickhouse-server/test_function.xml avec la configuration de chemin par défaut)./etc/clickhouse-server/test_function.xml
Query
Result
UDF à partir d’un script Python
STDIN et la renvoie sous forme de chaîne de caractères.
Créez test_function à l’aide d’une configuration XML ou YAML.
- XML
- YAML
Fichier
test_function.xml (/etc/clickhouse-server/test_function.xml avec le chemin par défaut)./etc/clickhouse-server/test_function.xml
Créez un fichier script
test_function.py dans le dossier user_scripts (/var/lib/clickhouse/user_scripts/test_function.py avec le chemin par défaut).
Query
Result
Lire deux valeurs à partir de STDIN et renvoyer leur somme sous forme d’objet JSON
test_function_sum_json avec des arguments nommés et le format JSONEachRow à l’aide d’une configuration XML ou YAML.
- XML
- YAML
Fichier
test_function.xml (/etc/clickhouse-server/test_function.xml avec les paramètres de chemin par défaut)./etc/clickhouse-server/test_function.xml
Créez le fichier de script
test_function_sum_json.py dans le dossier user_scripts (/var/lib/clickhouse/user_scripts/test_function_sum_json.py avec les paramètres de chemin par défaut).
Query
Result
Utiliser des paramètres dans le paramètre command
command (cela fonctionne uniquement pour les fonctions définies par l’utilisateur de type executable).
Cela nécessite également l’option execute_direct pour éviter toute vulnérabilité liée à l’expansion des arguments par le shell.
- XML
- YAML
Fichier
test_function_parameter_python.xml (/etc/clickhouse-server/test_function_parameter_python.xml avec les chemins par défaut)./etc/clickhouse-server/test_function_parameter_python.xml
Créez le script
test_function_parameter_python.py dans le dossier user_scripts (/var/lib/clickhouse/user_scripts/test_function_parameter_python.py avec les chemins par défaut).
Query
Result
UDF à partir d’un script shell
- XML
- YAML
Fichier
test_function_shell.xml (/etc/clickhouse-server/test_function_shell.xml si vous utilisez les chemins par défaut)./etc/clickhouse-server/test_function_shell.xml
Créez le fichier de script
test_shell.sh dans le dossier user_scripts (/var/lib/clickhouse/user_scripts/test_shell.sh si vous utilisez les chemins par défaut).
/var/lib/clickhouse/user_scripts/test_shell.sh
Query
Result
Gestion des erreurs
Évaluation des expressions des arguments
&&, || et ?:.
Dans ClickHouse, les arguments des fonctions (opérateurs) sont toujours évalués.
Cela s’explique par le fait que des parties entières de colonnes sont évaluées en une seule fois, au lieu de calculer chaque ligne séparément.
Exécution des fonctions pour le traitement distribué des requêtes
SELECT f(sum(g(x))) FROM distributed_table GROUP BY h(y),
- si
distributed_tablea au moins deux shards, les fonctions ‘g’ et ‘h’ sont exécutées sur des serveurs distants, et la fonction ‘f’ est exécutée sur le serveur à l’origine de la requête. - si
distributed_tablen’a qu’un seul shard, toutes les fonctions ‘f’, ‘g’ et ‘h’ sont exécutées sur le serveur de ce shard.
hostName, qui renvoie le nom du serveur sur lequel elle s’exécute, afin de permettre un GROUP BY par serveurs dans une requête SELECT.
Si une fonction d’une requête est exécutée sur le serveur à l’origine de la requête, mais que vous devez l’exécuter sur des serveurs distants, vous pouvez l’encapsuler dans une fonction d’agrégation ‘any’ ou l’ajouter à une clé du GROUP BY.
SQL User Defined Functions
WebAssembly User Defined Functions
Démarrage rapide
Informations complémentaires
Fonctions utilisateur exécutables basées sur un driver
Il s’agit d’une fonctionnalité expérimentale qui peut évoluer de façon non rétrocompatible dans les versions futures. Activez-la avec le paramètre serveur
allow_experimental_executable_udf_drivers.ENGINE = DriverName(...), ClickHouse exécute la commande create_command du driver en lui transmettant la signature de la fonction et le corps du code ; le driver compile ce corps ou le traite d’une autre manière, puis produit une configuration d’UDF exécutable, que ClickHouse stocke et charge ensuite.
Cela permet aux administrateurs d’offrir aux utilisateurs un moyen sûr et limité de définir des fonctions dans n’importe quel langage (par exemple, du C compilé dans un conteneur isolé) sans leur donner accès aux fichiers de configuration ni au système de fichiers du serveur. L’ensemble des drivers disponibles est entièrement contrôlé par l’opérateur.
Activation des drivers
-
Activez l’option expérimentale dans la configuration du serveur :
-
Faites pointer
user_defined_executable_function_drivers_configvers un ou plusieurs fichiers de configuration de driver (les motifs glob sont pris en charge) et, si nécessaire, définissezdynamic_user_defined_executable_functions_path, le répertoire où sont stockées les configurations générées des UDF exécutables :
SYSTEM RELOAD CONFIG, ce qui permet d’ajouter, de modifier ou de supprimer des drivers sans redémarrer le serveur.
Configuration du driver
<driver> à la racine. Les champs suivants sont pris en charge :
Exemple de configuration de driver :
Contrat d’invocation du driver
CREATE FUNCTION s’exécute, create_command est invoquée avec les variables env configurées et les arguments suivants :
--name <function_name>--return <return_type>(si une clauseRETURNSest présente)--args <signature>(si une clauseARGUMENTSest présente), où la signature correspond à la liste des arguments déclarés, par exemplex UInt8, y DateTime--<key> <value>pour chaque argument d’engine déclaré fourni dansENGINE = DriverName(key = value)
AS) est envoyé sur l’entrée standard de la commande. La commande doit écrire la configuration d’une UDF exécutable sur sa sortie standard. Le format est détecté automatiquement : toute sortie commençant par < est traitée comme du XML, sinon comme du YAML. Le nom de fonction défini dans la configuration générée doit correspondre au nom en cours de création. Si create_command se termine avec un code de sortie non nul, l’instruction échoue avec une exception qui inclut ce code de sortie ainsi que la sortie d’erreur standard du driver.
drop_command, lorsqu’elle est présente, est invoquée de la même manière (sans corps de code sur stdin) lors de la suppression de la fonction.
Création d’une fonction
create_command du driver, écrit la configuration générée dans dynamic_user_defined_executable_functions_path, puis le chargeur existant d’UDF exécutables la prend en charge. La fonction peut ensuite être appelée comme n’importe quelle autre fonction.
Suppression d’une fonction
DROP FUNCTION appelle le drop_command du driver (s’il est présent), supprime la configuration dynamique générée ainsi que le répertoire de travail associé à chaque fonction, recharge le chargeur des UDF exécutables et supprime la requête enregistrée.
Persistance et redémarrage
ATTACH FUNCTION ... dans le répertoire des objets SQL définis par l’utilisateur, de sorte que la fonction soit conservée après un redémarrage du serveur. Au démarrage, les configurations générées dans dynamic_user_defined_executable_functions_path sont chargées directement sans relancer le driver. Si une instruction ATTACH FUNCTION conservée n’a pas de configuration générée correspondante (par exemple, si le répertoire dynamique a été perdu), le driver est relancé pour la recréer.
Limites
- La fonctionnalité est expérimentale et activée via
allow_experimental_executable_udf_drivers. - Les fonctions basées sur des drivers ne sont pas prises en charge avec le stockage répliqué des fonctions définies par l’utilisateur (
ON CLUSTERet<user_defined_zookeeper_path>), car seule la requête initiale est répliquée, pas les artefacts générés. - Le
RESTOREd’une fonction basée sur un driver issue d’une sauvegarde conserve la requête, mais ne réexécute pas le driver ; la configuration générée n’est matérialisée que plus tard, lors de la reprise après redémarrage.
Exemple de drivers C
programs/server/user_defined_executable_function_drivers_config.d/ qui compilent et exécutent le corps d’une fonction C. Ce sont des exemples et ils ne sont pas installés par les paquets :
DockerC- compile et exécute le code dans des conteneurs Docker isolés (--network=none --read-only --cap-drop=ALL --security-opt=no-new-privileges, avec en plus des limites de mémoire/CPU/PID), en produisant une UDFexecutable_pool.GVisorC- une variante qui exécute le binaire compilé avec l’environnement d’exécutionrunscde gVisor.UnsafeC- compile et exécute le code directement sur l’hôte, sans sandbox. Comme son nom l’indique, il ne fournit aucune isolation et est destiné uniquement aux environnements de confiance et aux tests.