[PYTHON] Verwendung des JDBC-Treibers mit Redash

Redash unterstützt standardmäßig viele Datenquellen. Selbst wenn einige Datenquellen nicht unterstützt werden, können Sie neue Datenquellen hinzufügen, indem Sie query_runner in Python schreiben. Sie können query_runner direkt schreiben, wenn Sie über eine Python-Bibliothek verfügen, um eine Verbindung zur Zieldatenquelle herzustellen. Einige DBs stellen jedoch möglicherweise nur den JDBC-Treiber bereit. Da der JDBC-Treiber nur aus der JVM-Sprache aufgerufen werden kann, kann er nicht direkt in den query_runner von redash integriert werden. Daher habe ich eine Möglichkeit entwickelt, den JDBC-Treiber in redash zu integrieren. Dieser Artikel zeigt Ihnen, wie das geht.

Bibliothek zu verwenden

Diesmal ist es eine Bibliothek zum Aufrufen des JDBC-Treibers von Python. Verwenden Sie JayDeBeApi. https://github.com/baztian/jaydebeapi

Diese Bibliothek verwendet JPype in der CPython-Umgebung, um eine Brücke zwischen Python und Java zu schlagen. https://github.com/jpype-project/jpype

Es gibt Py4J als Bibliothek zum Aufrufen von Java aus Python und einen einführenden Artikel zu Qiita. Im Vergleich dazu scheint JPype jedoch leichter zu sein, da kein Java-Prozess gestartet werden muss.

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

Integrieren Sie den JDBC-Treiber in redash

Dieses Mal werden wir den JDBC-Treiber in redash v5.0.2 einbetten. Der einzuschließende JDBC-Treiber ist der von MySQL und kann von der folgenden URL heruntergeladen werden. https://dev.mysql.com/downloads/connector/j/5.1.html

Da Redash MySQL standardmäßig unterstützt, muss der JDBC-Treiber nicht zwangsweise eingebunden werden. Da es sich jedoch um eine weithin bekannte Datenbank handelt, wird sie zur Erläuterung verwendet.

jdbc.py Als nächstes schreiben Sie query_runner. Wie man query_runner schreibt, ist in den folgenden Artikeln gut organisiert. https://discuss.redash.io/t/creating-a-new-query-runner-data-source-in-redash/347

Ich habe den folgenden query_runner unter Bezugnahme auf den obigen Artikel erstellt.

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)

Ich denke, dass der größte Teil der Verarbeitung mit Ausnahme von configuration_schema gemeinsam verwendet werden kann, unabhängig davon, welcher JDBC-Treiber verwendet wird.

Anordnung verschiedener Dateien

Platzieren Sie die in der obigen Prozedur erstellte jdbc.py und die JDBC-Treiber-JAR-Datei in redash / query_runner.

Dockerfile Erstellen Sie schließlich einen Docker-Container, um Redash auszuführen. Da für JPype JRE erforderlich ist, patchen Sie die Redash-Standard-Docker-Datei. Erstellen Sie außerdem die Datei require.txt, um jaydebeapi zu installieren.


FROM redash/base:latest

#JRE-Installation hinzugefügt
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

Starten Sie Redash

An diesem Punkt können Sie mit dem Redash beginnen. Um den hinzugefügten query_runner in redash zu laden, muss außerdem "redash.query_runner.jdbc" zur Umgebungsvariablen "REDASH_ADDITIONAL_QUERY_RUNNERS" hinzugefügt und gestartet werden.

Wenn Sie mit dem Redash beginnen und den DataSource-Bildschirm anzeigen, sehen Sie, dass eine Datenquelle namens JDBC hinzugefügt wurde.

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

Im Moment sieht es etwas enttäuschend aus, da es kein Symbolbild gibt, das die Datenquelle zeigt. Um ein Bild in diesen Teil einzufügen, platzieren Sie das Bild "jdbc.png " in "client / app / assets / images / db-logos" und erstellen Sie den Container erneut.

Führen Sie eine Abfrage aus

Nachdem wir den JDBC-Treiber als query_runner registriert haben, führen wir die Abfrage aus.

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

Zusammenfassung

Mit JayDeBeApi konnte ich den JDBC-Treiber mit Redash verwenden. Damit hat sich die Vielfalt der Redash-Datenquellen erweitert, und Sie können ein wundervolles BI-Leben führen.

Recommended Posts

Verwendung des JDBC-Treibers mit Redash
Python: So verwenden Sie Async mit
So verwenden Sie virtualenv mit PowerShell
Verwendung von ManyToManyField mit Djangos Admin
Verwendung von OpenVPN mit Ubuntu 18.04.3 LTS
Verwendung von Cmder mit PyCharm (Windows)
Wie man Ass / Alembic mit HtoA benutzt
Verwendung von Japanisch mit NLTK-Plot
Verwendung des Jupyter-Notebooks mit ABCI
Verwendung von SQLAlchemy / Connect mit aiomysql
Verwendung von xml.etree.ElementTree
Verwendung von virtualenv
Wie benutzt man Seaboan?
Verwendung von Image-Match
Wie man Shogun benutzt
Verwendung von Pandas 2
Verwendung von Virtualenv
Verwendung von numpy.vectorize
Verwendung von pytest_report_header
Wie man teilweise verwendet
Verwendung von SymPy
Wie man x-means benutzt
Verwendung von WikiExtractor.py
Verwendung von IPython
Verwendung von virtualenv
Wie benutzt man Matplotlib?
Verwendung von iptables
Wie benutzt man numpy?
Verwendung von TokyoTechFes2015
Wie benutzt man venv
Verwendung des Wörterbuchs {}
Wie benutzt man Pyenv?
Verwendung der Liste []
Wie man Python-Kabusapi benutzt
Verwendung von OptParse
Wie man Imutils benutzt
Verwendung der GCP-Ablaufverfolgung mit offener Telemetrie
Wie man tkinter mit Python in Pyenv benutzt
Verwendung der Suche sortiert
[gensim] Verwendung von Doc2Vec
Verstehen Sie, wie man Django-Filter verwendet
Verwendung des Generators
[Python] Verwendung von Liste 1
Verwendung von FastAPI ③ OpenAPI
Verwendung des interaktiven Python-Modus mit Git Bash
Wie benutzt man Python Argparse?
Verwendung von IPython Notebook
Wie aktualisiere ich mit SQLAlchemy?
Wie man Pandas Rolling benutzt
[Hinweis] Verwendung von virtualenv
Verwendung von Redispy-Wörterbüchern
Python: Wie man pydub benutzt
[Python] Verwendung von checkio
[Go] Verwendung von "... (3 Perioden)"
Wie mit SQLAlchemy ändern?
Autoencoder im Chainer (Hinweise zur Verwendung von + Trainer)
So bedienen Sie GeoIp2 von Django