[PYTHON] Comment utiliser le pilote JDBC avec Redash

Redash prend en charge de nombreuses sources de données par défaut. De plus, même si certaines sources de données ne sont pas prises en charge, vous pouvez ajouter de nouvelles sources de données en écrivant query_runner en Python. Vous pouvez écrire simplement query_runner si vous disposez d'une bibliothèque Python pour vous connecter à la source de données cible, mais certaines bases de données peuvent fournir uniquement le pilote JDBC. Étant donné que le pilote JDBC ne peut être appelé qu'à partir du langage JVM, il ne peut pas être intégré directement dans le query_runner de redash. J'ai donc conçu un moyen d'incorporer le pilote JDBC dans Redash, et cet article vous montrera comment le faire.

Bibliothèque à utiliser

Cette fois, il s'agit d'une bibliothèque pour appeler le pilote JDBC depuis Python. Utilisez JayDeBeApi. https://github.com/baztian/jaydebeapi

Cette bibliothèque utilise JPype dans l'environnement CPython pour faire le pont entre Python et Java. https://github.com/jpype-project/jpype

Il existe Py4J en tant que bibliothèque pour appeler Java à partir de Python, et il existe un article d'introduction sur Qiita, mais comparé à cela, JPype semble être plus léger car il n'a pas besoin de démarrer un processus Java.

https://www.py4j.org/ https://qiita.com/riverwell/items/e90cbbfdac439e6e9d30

Incorporer le pilote JDBC dans Redash

Cette fois, nous intégrerons le pilote JDBC dans redash v5.0.2. Le pilote JDBC à inclure est celui de MySQL, et vous pouvez le télécharger à partir de l'URL suivante. https://dev.mysql.com/downloads/connector/j/5.1.html

Puisque Redash prend en charge MySQL en standard, il n'est pas nécessaire d'incorporer de force le pilote JDBC, mais comme il s'agit d'une base de données largement connue, il est utilisé pour l'explication.

jdbc.py Ensuite, écrivez query_runner. Comment écrire query_runner est bien organisé dans les articles suivants. https://discuss.redash.io/t/creating-a-new-query-runner-data-source-in-redash/347

J'ai créé le query_runner suivant en me référant à l'article ci-dessus.

import json
import logging
import os
import jaydebeapi

from redash.query_runner import *
from redash.settings import parse_boolean
from redash.utils import JSONEncoder

logger = logging.getLogger(__name__)
types_map = {
    jaydebeapi.STRING: TYPE_STRING,
    jaydebeapi.TEXT: TYPE_STRING,
    jaydebeapi.NUMBER: TYPE_INTEGER,
    jaydebeapi.FLOAT: TYPE_FLOAT,
    jaydebeapi.DECIMAL: TYPE_FLOAT,
    jaydebeapi.DATE: TYPE_DATE,
    jaydebeapi.DATETIME: TYPE_DATETIME,
    jaydebeapi.ROWID: TYPE_STRING,
}

class Jdbc(BaseSQLQueryRunner):
    noop_query = "SELECT 1"

    @classmethod
    def configuration_schema(cls):
        schema = {
            'type': 'object',
            'properties': {
                'host': {
                    'type': 'string',
                },
                'port': {
                    'type': 'number',
                    'default': 3306,
                },
                'user': {
                    'type': 'string'
                },
                'password': {
                    'type': 'string',
                },
                'database': {
                    'type': 'string',
                },
            },
            "order": ['host', 'port', 'user', 'password', 'database'],
            'required': ['host', 'port', 'user', 'database'],
            'secret': ['password']
        }

        return schema

    @classmethod
    def name(cls):
        return "jdbc"

    @classmethod
    def enabled(cls):
        try:
            import jaydebeapi
        except ImportError:
            return False

        return True

    def _get_tables(self, schema):
        query = """
        SELECT col.table_schema,
               col.table_name,
               col.column_name
        FROM `information_schema`.`columns` col
        WHERE col.table_schema NOT IN ('information_schema', 'performance_schema', 'mysql');
        """

        results, error = self.run_query(query, None)
        if error is not None:
            raise Exception("Failed getting schema.")

        results = json.loads(results)

        for row in results['rows']:
            if row['TABLE_SCHEMA'] != self.configuration['database']:
                table_name = u'{}.{}'.format(row['TABLE_SCHEMA'], row['TABLE_NAME'])
            else:
                table_name = row['TABLE_NAME']

            if table_name not in schema:
                schema[table_name] = {'name': table_name, 'columns': []}

            schema[table_name]['columns'].append(row['COLUMN_NAME'])

        return schema.values()

    def run_query(self, query, user):
        import jaydebeapi

        connection = None
        try:
            host = self.configuration.get('host', '')
            port = self.configuration.get('port', '')
            user = self.configuration.get('user', '')
            password = self.configuration.get('password', '')
            database = self.configuration.get('database', '')

            jclassname = 'com.mysql.jdbc.Driver'
            url = 'jdbc:mysql://{}:{}/{}'.format(host, port, database)
            driver_args = {'user': user, 'password': password}
            jar_path = '/app/redash/query_runner/mysql-connector-java-5.1.47.jar'
            connection = jaydebeapi.connect(jclassname, url, driver_args, jar_path)

            cursor = connection.cursor()
            logger.info("JDBC running query: %s", query)
            cursor.execute(query)

            data = cursor.fetchall()

            if cursor.description is not None:
                columns = self.fetch_columns([(i[0], types_map.get(i[1], None)) for i in cursor.description])
                rows = [dict(zip((c['name'] for c in columns), row)) for row in data]

                data = {'columns': columns, 'rows': rows}
                json_data = json.dumps(data, cls=JSONEncoder)
                error = None
            else:
                json_data = None
                error = "No data was returned."

            cursor.close()
        except jaydebeapi.Error as e:
            json_data = None
            error = str(e.message)
        except KeyboardInterrupt:
            cursor.close()
            error = "Query cancelled by user."
            json_data = None
        finally:
            if connection:
                connection.close()

        return json_data, error

register(Jdbc)

Je pense que la plupart des traitements, à l'exception de configuration_schema, peuvent être utilisés en commun quel que soit le pilote JDBC utilisé.

Disposition de divers fichiers

Placez le jdbc.py créé dans la procédure ci-dessus et le fichier jar du pilote JDBC dans redash / query_runner.

Dockerfile Enfin, créez un conteneur Docker pour exécuter Redash. Étant donné que JRE est requis pour que JPype fonctionne, corrigez le fichier Dockerfile standard redash. Créez également requirements.txt pour installer jaydebeapi.


FROM redash/base:latest

#Ajout de l'installation de JRE
RUN apt-get update && apt-get install -y openjdk-8-jre

COPY redash/requirements.txt redash/requirements_dev.txt redash/requirements_all_ds.txt requirements_jaydebeapi.txt ./
RUN pip install -r requirements.txt -r requirements_dev.txt -r requirements_all_ds.txt -r requirements_jaydebeapi.txt

COPY . ./
RUN npm install && npm run build && rm -rf node_modules
RUN chown -R redash /app
USER redash

ENTRYPOINT ["/app/bin/docker-entrypoint"]
CMD ["server"]

requirements.txt


JayDeBeApi==1.1.1
JPype1==0.6.3

Démarrer redash

À ce stade, vous pouvez démarrer Redash. De plus, pour charger le query_runner ajouté dans redash, il est nécessaire d'ajouter redash.query_runner.jdbc à la variable d'environnement REDASH_ADDITIONAL_QUERY_RUNNERS et de le démarrer.

Si vous démarrez Redash et regardez l'écran DataSource, vous pouvez voir qu'une source de données appelée JDBC a été ajoutée.

スクリーンショット 2018-11-29 14.28.28.png

Pour le moment, cela semble un peu décevant car il n'y a pas d'image d'icône montrant la source de données. Pour mettre une image dans cette partie, placez l'image jdbc.png dans client / app / assets / images / db-logos et reconstruisez le conteneur.

Exécuter une requête

Maintenant que nous avons enregistré le pilote JDBC en tant que query_runner, exécutons la requête.

スクリーンショット 2018-11-29 14.30.45.png

Résumé

En utilisant JayDeBeApi, j'ai pu utiliser le pilote JDBC avec redash. Avec cela, la variété des sources de données redash s'est étendue et vous pouvez avoir une vie BI merveilleuse.

Recommended Posts

Comment utiliser le pilote JDBC avec Redash
Python: comment utiliser async avec
Pour utiliser virtualenv avec PowerShell
Comment utiliser ManyToManyField avec l'administrateur de Django
Comment utiliser OpenVPN avec Ubuntu 18.04.3 LTS
Comment utiliser Cmder avec PyCharm (Windows)
Comment utiliser Ass / Alembic avec HtoA
Comment utiliser le japonais avec le tracé NLTK
Comment utiliser le notebook Jupyter avec ABCI
Comment utiliser SQLAlchemy / Connect avec aiomysql
Comment utiliser xml.etree.ElementTree
Comment utiliser virtualenv
Comment utiliser Seaboan
Comment utiliser la correspondance d'image
Comment utiliser le shogun
Comment utiliser Pandas 2
Comment utiliser Virtualenv
Comment utiliser numpy.vectorize
Comment utiliser pytest_report_header
Comment utiliser partiel
Comment utiliser SymPy
Comment utiliser x-means
Comment utiliser WikiExtractor.py
Comment utiliser IPython
Comment utiliser virtualenv
Comment utiliser Matplotlib
Comment utiliser iptables
Comment utiliser numpy
Comment utiliser TokyoTechFes2015
Comment utiliser venv
Comment utiliser le dictionnaire {}
Comment utiliser Pyenv
Comment utiliser la liste []
Comment utiliser python-kabusapi
Comment utiliser OptParse
Comment utiliser pyenv-virtualenv
Comment utiliser imutils
Comment utiliser la trace GCP avec la télémétrie ouverte
Comment utiliser tkinter avec python dans pyenv
Comment utiliser la recherche triée
[gensim] Comment utiliser Doc2Vec
Comprendre comment utiliser django-filter
Comment utiliser le générateur
[Python] Comment utiliser la liste 1
Comment utiliser FastAPI ③ OpenAPI
Comment utiliser le mode interactif python avec git bash
Comment utiliser Python Argparse
Comment utiliser IPython Notebook
Comment mettre à jour avec SQLAlchemy?
Comment utiliser Pandas Rolling
[Note] Comment utiliser virtualenv
Comment utiliser les dictionnaires redis-py
Python: comment utiliser pydub
[Python] Comment utiliser checkio
[Aller] Comment utiliser "... (3 périodes)"
Comment modifier avec SQLAlchemy?
Autoencoder dans Chainer (Remarques sur l'utilisation de + trainer)
Comment faire fonctionner GeoIp2 de Django