TabPy pour travailler avec des données dans ClickHouse de Tableau

Développer la communication entre les marques et les gens est ce que nous faisons quotidiennement chez Dentsu Aegis Network, et l'analyse des données fait partie intégrante de ce travail. Dans certains cas, ce processus ne nécessite pas de science des données (bien que nous en ayons un), nous utilisons alors la plateforme Tableau BI. Son objectif principal est de fournir à nos employés et clients une interface pratique pour la consommation de données sans écrire de scripts, de requêtes SQL, etc.

Dans cet article, nous décrirons comment nous avons réussi à résoudre le problème d'interaction de Tableau avec ClickHouse .

Énoncé général du problème


Nous avons fait face à un défi classique. Nous avons des gens. Ils aiment les fruits. Certaines personnes aiment un fruit, d'autres comme tous les fruits, et les autres peuvent aimer n'importe quelle combinaison de fruits.
image
Il est donc nécessaire de permettre à l'utilisateur du tableau de bord intégré à Tableau de sélectionner arbitrairement plusieurs fruits et de voir combien de personnes aiment au moins un fruit de l'ensemble. Bien sûr, nous n'avions pas de fruits, mais les gens étaient réels, c'est juste que sur les «fruits», il est plus facile de comprendre le problème.

La quantité de données dans notre cas est assez importante. Il y avait 13 mille «fruits» différents. Le «fruit» le plus populaire comptait près de 34 millions de fans. En moyenne, 450 000 personnes aiment chaque «fruit». Total des amateurs de fruits - 282 millions.

Première solution frontale


Il se trouve que les données de cette tâche que nous avions dans PostgreSQL (PG) et ClickHouse (CH). En PG, il y avait un tableau de référence sur les «fruits», en CH - un grand tableau avec une structure: l'identifiant du «fruit» et l'identifiant de la personne qui aime ce «fruit». Il n'y a pas de connecteur natif pour CH dans Tableau, et je ne voulais toujours pas transférer les données quelque part, car cela nécessiterait une refonte sérieuse du système existant.

Nous avons essayé de connecter Tableau à CH à l'aide du pilote ODBC et de voir ce qui se passe.

  • Tous les pilotes ODBC ne sont pas également utiles. Nous avons besoin d'une certaine version dans laquelle fonctionne la partie nécessaire de la fonctionnalité, mais rien ne garantit que le reste fonctionnera si vous en avez soudainement besoin.
  • Nous n'avons pas pu extraire toutes les données dans l'extrait de Tableau, car il s'agit de 13 000 * 450 000 = 5 850 000 000 d'enregistrements.

Ensuite, nous avons décidé d'utiliser l'échantillonnage à l'intérieur de la requête vers la base de données CH, c'est-à-dire pour faire notre estimation du nombre d'amoureux de la combinaison de «fruits» sélectionnée non pas sur toutes les personnes, mais sur un échantillon de cinq pour cent pour réduire l'extrait. De plus, nous avons immédiatement effectué une extraction de jointure interne à partir de CH avec un répertoire PG «fruit» pour obtenir les noms «fruit». Cela a aidé - notre extrait a pu être généré en 5 heures.

Nous devions mettre à jour les données dans le tableau de bord une fois par jour, donc 5 heures de mise à jour de l'extrait semblent être correctes - nous mettrons à jour la nuit. Mais à l'avenir, nous aurions besoin de capacités supplémentaires: il devrait y avoir plus de «fruits»; en conséquence, le nombre et la taille des groupes de personnes dont nous devions calculer l'intersection devrait également augmenter. Par conséquent, une longue mise à jour de l'extrait n'est pas du tout notre option.

De plus, il y avait un autre problème dû à l'échantillonnage. Il se trouve que dans différentes parties du tableau de bord, les chiffres, qui devraient être censés coïncider, étaient différents dans notre pays. Cela était dû au fait qu'en un seul endroit, nous avons compté le nombre d'amoureux d'un fruit avec précision, et en partie avec une combinaison de fruits - inexact. Ni nous ni nos utilisateurs n'avons aimé ce résultat.

Ensuite, nous avons décidé de ne pas créer d'extrait du tout. Pour éviter de charger une énorme quantité de données, nous avons divisé les ensembles de données et utilisé la connexion en direct pour CH. Entre les jeux de données, une connexion a été établie à l'aide de la fonctionnalité de relation Tableau Edit intégrée. La source de données PG a été rendue principale et liée à CH comme secondaire, en utilisant l'identifiant «fruit» qui était dans les deux tableaux.

Ainsi, nous avons pu filtrer la source de données secondaire en utilisant le primaire (mélange de données). Mais nous nous attendions à un échec, car après avoir lancé le filtre d'une source de données à une autre, nous avons dû utiliser la fonction de comptage des personnes dans le sous-ensemble résultant (COUNTD), et le mélange de données a une limitation qui ne permet tout simplement pas de le faire. Une telle fonction directement avec une telle connexion de données ne fonctionne pas en principe.

Il existe une solution de contournement qui permet de contourner cette limitation de Tableau, mais elle peut être utilisée sur des ensembles de données relativement petits, ce qui n'est clairement pas le cas dans notre cas.

Après cela, nous avons essayé une autre option. Les ensembles de données étaient toujours divisés et utilisaient une connexion en direct pour CH. Ici, le filtre de l'ensemble de données avec la description de «fruits» à l'ensemble de données avec des fans de «fruits» a été lancé dans Tableau à l'aide de l'action set. Mais cette option ne convenait finalement pas en raison de l'interface utilisateur peu pratique. Au lieu du filtre familier à l'utilisateur, l'utilisateur devrait regarder la liste entière et sélectionner "fruits" via cntrl + clic, tandis que la fonction d'application était absente lorsque toutes les valeurs sélectionnées sont appliquées en même temps.

En conséquence, après toutes nos tentatives, nous avons dû revenir à l'option avec extrait et échantillonnage, terriblement lente et ne donnant qu'une réponse approximative.

image

Solution trouvée


De toute évidence, nous n'avons pas besoin d'extraire toutes les données dans l'extrait de Tableau. L'utilisateur est mal à l'aise de voir toutes les données à la fois - le nombre de personnes qui aiment tous les «fruits». Il a besoin d'un ensemble d'une moyenne de 10 «fruits». Il est dommage que Tableau ne sache pas comment procéder.

Il y a des gars dans notre équipe qui écrivent en Python. Par conséquent, nous avons décidé dans notre recherche d'aller dans cette direction et avons trouvé TabPy .

TabPy est un service Web qui vous permet d'obtenir le résultat de l'exécution de scripts Python dans Costing dans Tableau.

Comment ça marche:

  1. Tableau interagit avec TabPy et, à son tour, avec Python en utilisant les soi-disant fonctions de script. Les fonctions de script contiennent le script Python lui-même, le type de données requis du résultat et les arguments que nous transmettons à cette fonction. Dans notre cas, les arguments étaient des identifiants de «fruits», le nombre d'amants dont nous voulions compter.
  2. TabPy convertit le texte reçu des fonctions de script en script et le transmet à l'interpréteur. La connexion à la base CH a été enregistrée par nous dans le script.
  3. Ensuite, TabPy renvoie le résultat du script exécuté à Tableau.


image

Dans les fonctions de script, les arguments sont toujours transmis sous forme de tableaux; le résultat est également renvoyé par un tableau.

Tout n'a pas fonctionné tout de suite. La principale chose que nous avons comprise: écrire un script Python directement dans un champ calculé dans Tableau n'est pas une bonne idée. Pour deux raisons:

  1. Dans les fonctions de script, il est parfois difficile d'utiliser la syntaxe Python familière. Par exemple, plusieurs devis ne sont pas acceptés.
  2. En pensant à la prise en charge future du tableau de bord, nous avons réalisé que si nous devons changer le script d'une manière ou d'une autre, nous devrons à chaque fois le changer dans le livre Tableau lui-même. Et ce n'est clairement pas la meilleure façon, car nous faisons de notre mieux pour éviter la prise en charge manuelle des tableaux de bord.

Par conséquent, nous avons utilisé une autre chose - TabPy Client .

TabPy Client est une bibliothèque qui vous permet de publier des scripts Python sur le serveur TabPy, puis de les appeler dans Tableau. Lorsque vous l'utilisez, au lieu d'écrire un script dans Tableau, nous appelons le fichier .py se trouvant sur le serveur TabPy en utilisant les paramètres qui y sont spécifiés, lui transmettons des arguments et l'exécutons.

Cette approche a résolu nos problèmes en utilisant TabPy et Tableau. Le script est écrit et testé dans l'environnement de développement familier et stocké séparément du livre, qui ne nécessite désormais plus de prise en charge manuelle.

Pour résoudre notre problème spécifique, nous avons dû procéder comme suit.
Au début, nous avons essayé de le résoudre sans utiliser le client TabPy. Dans ce cas, un champ de calcul du formulaire suivant a été créé dans Tableau:
SI PREMIER () == 0
ALORS
SCRIPT_INT ("
depuis le client d'importation clickhouse_driver
client = Client (hôte = nom_hôte, base de données = nom_base de données, utilisateur = nom_utilisateur, mot de passe = mot de passe)

----- script_text -----

", SUM ([people]), ATTR ([fruits_id]))
Fin
Cela a fonctionné, mais il y avait des problèmes qui ont été décrits ci-dessus. Lorsque nous avons compris le client TabPy, nous avons réalisé qu'en divisant le champ Calcul et le script lui-même, nous obtenons un système plus pratique et correct. Voici à quoi ressemblaient le champ Calcul et le fichier .py avec le script:
Champ de calculSCRIPT_INT ("
return tabpy.query ('people_count_test', _ arg1, _arg2) ['response']
", SUM ([people]), ATTR ([fruits_id]))
Fichier .pydepuis le client d'importation clickhouse_driver
importer tabpy_client
connection = tabpy_client.Client ('http: // localhost: 9004 /')
def unique_people_count (people, fruits_id):
client = Client (hôte = nom_hôte, base de données = nom_base de données, utilisateur = nom_utilisateur, mot de passe = mot de passe)

----- script_text -----

connection.deploy ('people_count_test', unique_people_count, 'comment', override = True)
Ici, vous pouvez voir que 'people_count_test' est l'identifiant du client TabPy, grâce auquel il est clair quel script exécuter dans ce champ de calcul.

Et au final, c'est cette approche qui nous a totalement satisfaits.

image

Résumé


Les utilisateurs sont satisfaits car ils peuvent choisir arbitrairement une combinaison de «fruits» et obtenir rapidement le nombre de fans d'au moins l'un d'entre eux, et les chiffres dans les différentes parties du tableau de bord sont les mêmes.

Les développeurs BI sont heureux que vous puissiez travailler avec ClickHouse de Tableau, sans avoir à vous y connecter directement.

Notre Tableau Server est heureux que vous n'ayez pas besoin de faire un énorme extrait la nuit.

En général, TabPy donne aux développeurs BI plus de liberté pour travailler avec des données lorsque Tableau ne dispose pas d'une solution appropriée prête à l'emploi. Par exemple, pour intégrer des modèles de science des données directement dans Tableau, mais c'est une toute autre histoire ...

L'article a été rédigé conjointement avec mes collègues Dimitri Shcherbenko ( dima_vs ) et Sukhoveev Ivan ( suho_v ) R&D Dentsu Aegis Network Russia.

Source: https://habr.com/ru/post/fr477864/


All Articles