Python で Denodo に接続！SQLAlchemy と psycopg2 を使ったデータ取得

こんにちは、インサイトテクノロジーの松尾です！

本記事では、**Python から Denodo Platform のデータを扱う方法**をいくつかご紹介します。

## はじめに

Denodo Platform は、データ仮想化テクノロジーを活用した論理データ統合のための製品です。  
「データ統合」というと、ETL ツールやレプリケーションツールを使い、大きな「箱」にデータを集めるイメージを思い浮かべるかもしれません。  
しかし、Denodo Platform の「論理データ統合」では、データを物理的に移動させるのではなく、**あたかもデータが一か所に集まっているように見せる**ことがコンセプトとなっています。

Denodo Platform の詳細については、以下のリンクをご覧ください。

https://qiita.com/takumats/items/d293a743bb7f78e16b0b

https://www.denodo.com/ja/denodo-platform/denodo-platform?utm_source=partner_lead_InsightTech

Denodo Platform によって仮想的に統合されたデータは、Denodo Platform を介して取得できます。JDBC、ODBC、REST API、GraphQL など、多様なアクセス方法が標準サポートされており、BI ツールやプログラミング言語から容易に接続可能です。

本記事では、Denodo 社が公開しているドキュメント  
[How to connect to Denodo from Python - a starter for Data Scientists](https://community.denodo.com/kb/en/view/document/How%20to%20connect%20to%20Denodo%20from%20Python%20-%20a%20starter%20for%20Data%20Scientists?utm_source=partner_lead_InsightTech)  
を参考に、いくつかの接続方法を実際に試してみます。

## 接続方法

Python から Denodo Platform へ接続するために使用できる Python ライブラリはいくつかあります。  
以下の表に主なライブラリをまとめました。

| Library | Denodo Interface | コメント |
|---|---|---|
| [Denodo Dialect for SQLAlchemy](https://community.denodo.com/docs/html/document/denodoconnects/9.1/en/Denodo%20Dialect%20for%20SQLAlchemy%20-%20User%20Manual?utm_source=partner_lead_InsightTech) | ODBC/libpq | SQLAlchemy は Python の SQL ツールキット兼 ORM。SQL の強力な機能と柔軟性を提供。 |
| [psycopg2](https://www.psycopg.org/) | ODBC/libpq | PostgreSQL 用の一般的なアダプターで、Denodo でも使用可能。 |
| [turbodbc](https://turbodbc.readthedocs.io/en/latest/) | ODBC | データサイエンティスト向けのライブラリで、NumPy や Apache Arrow の最適化が特徴。 |
| [pyodbc](https://mkleehammer.github.io/pyodbc/) | ODBC | 一般的な ODBC ベースのライブラリで、リレーショナルデータベースへの接続に広く利用。 |
| [jaydebeapi](https://github.com/baztian/jaydebeapi) | JDBC | JDBC ベースの Python ライブラリで、JPype を利用して Python と Java のコードを橋渡し。 |

これらのライブラリは、Denodo を **"DB" として接続** して利用するパターンになります。  
Denodo は REST API や GraphQL によるデータ公開も可能ですが、Python から利用する場合は **"DB" として接続する方が便利** でしょう。

## オススメの接続方法は？

[Denodo 社のサイト](https://community.denodo.com/kb/en/view/document/How%20to%20connect%20to%20Denodo%20from%20Python%20-%20a%20starter%20for%20Data%20Scientists#h.tdqkbm3po90r?utm_source=partner_lead_InsightTech) によると、通常は **SQLAlchemy** または **psycopg2** が推奨されています。  
これらを使用する場合、**Denodo ODBC ドライバーのインストールは不要**です。

### Kerberos や OAuth2 認証が必要な場合
Kerberos や OAuth2 認証を利用する場合は、**Denodo ODBC ドライバーを使用する必要がある**ため、この場合は **turbodbc** ライブラリの使用が推奨されています。

### 推奨されない接続方法
一方で、**pyodbc や jaydebeapi はパフォーマンスの観点から推奨されていません**。

本記事では、推奨されている **SQLAlchemy** および **psycopg2** を用いた接続方法を、実際に試しながら紹介します。

## テストの条件

### 実施環境
- OS: Windows 11 Pro, WSL2 (Ubuntu 24.04.1 LTS)
- Python: 3.12.3
- Denodo 環境: 9.1（コンテナで起動）
- 接続先（ODBC）
  - ホスト: `localhost`
  - ポート番号: `9996`
  - データベース（VDB）: `admin`
  - ユーザー: `admin`
  - パスワード: `admin`

コンテナでの Denodo 環境の起動については、以下の記事を参考にしてください。 

https://qiita.com/takumats/items/c26734b7ab05814c533a

### テストに使用するデータソース

テスト用のデータソースとして、[Denodo Community Lab Environment Containers](https://github.com/denodo/denodocommunity-lab-environment/tree/master/lab-environment-containers#data-sources) で提供されているものを使用します。ローカル環境でコンテナ起動している場合、以下の設定でデータソースを登録することができます。さらに登録したデータソースから、ベースビューを作成して利用します。

- データソースの種類: Excel ファイルデータソース
- ベース URL: `http://webserver:80/excel/Marketing_promotions.xlsx`
- 開始セル: `A1`
- ヘッダーを使用する: チェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480312/b9815360-a7f7-1927-f2a0-acf7f4ec3da8.png)

上記の設定でデータソース登録後、ベースビュー(基本ビュー)を `bv_excel_marketing_promotion` という名前で作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480312/55528388-704c-fb00-6f6f-b0fad7a86438.png)

## Denodo Dialect for SQLAlchemy による接続

### SQLAlchemy のインストール

Denodo Dialect for SQLAlchemy は `pip` でインストールできます。  
以下の 3 つのモジュールをインストールします。

- `denodo-sqlalchemy`
- `pyarrow`
- `adbc_driver_flightsql`

```bash
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ source venv/bin/activate
(venv) $ pip3 install denodo-sqlalchemy
(venv) $ pip3 install pyarrow
(venv) $ pip3 install adbc_driver_flightsql
(venv) $ pip3 list
Package               Version
--------------------- -------
adbc-driver-flightsql 1.4.0
adbc-driver-manager   1.4.0
denodo-sqlalchemy     2.0.2
greenlet              3.1.1
importlib_resources   6.5.2
pip                   24.0
psycopg2-binary       2.9.10
pyarrow               19.0.0
SQLAlchemy            2.0.37
typing_extensions     4.12.2
```

### SQLAlchemy を使用した Python コードと実行例

以下のような Python コードを作成します。

```python
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

# ベースクラスを定義
Base = declarative_base()

# テーブルの定義
class MarketingPromotion(Base):
    __tablename__ = "bv_excel_marketing_promotion"

    promotion_id = Column(Integer, primary_key=True)
    description = Column(String)
    startdate = Column(String)
    enddate = Column(String)
    area = Column(String)
    promotion_type = Column(String)
    discount = Column(String)
    channel = Column(String)

# Denodo VDP Server の接続情報
denodoserver_name = "localhost"
denodoserver_odbc_port = "9996"
denodoserver_database = "admin"
denodoserver_uid = "admin"
denodoserver_pwd = "admin"

# 接続文字列
cnxn_str = "denodo://%s:%s@%s:%s/%s" %\
       (denodoserver_uid, denodoserver_pwd, denodoserver_name, denodoserver_odbc_port, denodoserver_database)

# データベース接続
engine = create_engine(cnxn_str)
Session = sessionmaker(bind=engine)
session = Session()

# 全データを取得
marketingPromotions = session.query(MarketingPromotion).all()
for promo in marketingPromotions:
    print(promo.promotion_id, promo.description, promo.area, promo.promotion_type, promo.startdate)
```

実行すると以下のようなイメージでデータを取得することができました！

```bash
(venv) $ python3 test.py
0 Winter Sale italy Other Jan 1, 2014 12:00:00 AM
1 Spring Big sale Italy Free items Mar 1, 2014 12:00:00 AM
2 Summer Event Italy Free items Jun 1, 2014 12:00:00 AM
3 Fall Push IT Instant rebate Aug 1, 2014 12:00:00 AM
4 Summer Event IT Other Nov 1, 2014 12:00:00 AM
5 Winter Sale Italy Other Dec 1, 2014 12:00:00 AM
6 Summer Event USA Other Jan 1, 2014 12:00:00 AM
7 Spring Push United States Instant rebate Mar 1, 2014 12:00:00 AM
8 Summer Push United States Instant rebate Jun 1, 2014 12:00:00 AM
9 Fall Big sale America Other Aug 1, 2014 12:00:00 AM
:
:
```

Python から SQLAlchemy を使って Denodo に接続し、Excel ファイルからデータを取得 する方法を紹介しました。

## psycopg2 による接続

### psycopg2 のインストール

`psycopg2` は `pip` でインストールできます。

```bash
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip3 install psycopg2-binary
(venv) $ pip3 list
Package         Version
--------------- -------
pip             24.0
psycopg2-binary 2.9.10
```

### psycopg2 を使用した Python コードと実行例

例えば以下のような Python コードを作成します。

```python
import psycopg2 as dbdriver

## Denodo VDP Server の接続情報
denodoserver_name = "localhost"
denodoserver_odbc_port = "9996"
denodoserver_database = "admin"
denodoserver_uid = "admin"
denodoserver_pwd = "admin"

## 接続文字列の作成
cnxn_str = "user=%s password=%s host=%s dbname=%s port=%s" %\
       (denodoserver_uid, denodoserver_pwd, denodoserver_name, denodoserver_database, denodoserver_odbc_port)
## データベース接続
cnxn = dbdriver.connect(cnxn_str)

# クエリを実行
query = "select * from admin.bv_excel_marketing_promotion"
cur = cnxn.cursor()
cur.execute(query)

# 結果を取得
rows = cur.fetchall()
for row in rows:
    print(row)
```

実行すると以下のようなイメージでデータを取得することができました！

```bash
(venv) $ python3 test.py
(0, 'Winter Sale', 'Jan 1, 2014 12:00:00 AM', 'Jan 1, 2014 12:00:00 AM', 62, 'italy', 'Other', Decimal('0.583401707007053'), 'TV')
(1, 'Spring Big sale', 'Mar 1, 2014 12:00:00 AM', 'Mar 1, 2014 12:00:00 AM', 31, 'Italy', 'Free items', Decimal('0.567807718602781'), 'Phone')
(2, 'Summer Event', 'Jun 1, 2014 12:00:00 AM', 'Jun 1, 2014 12:00:00 AM', 36, 'Italy', 'Free items', Decimal('0.650828660849123'), 'Web')
(3, 'Fall Push', 'Aug 1, 2014 12:00:00 AM', 'Aug 1, 2014 12:00:00 AM', 62, 'IT', 'Instant rebate', Decimal('0.666344228317836'), 'TV')
(4, 'Summer Event', 'Nov 1, 2014 12:00:00 AM', 'Nov 1, 2014 12:00:00 AM', 86, 'IT', 'Other', Decimal('0.190036937133527'), 'TV')
(5, 'Winter Sale', 'Dec 1, 2014 12:00:00 AM', 'Dec 1, 2014 12:00:00 AM', 19, 'Italy', 'Other', Decimal('0.609010749315586'), 'Email')
(6, 'Summer Event', 'Jan 1, 2014 12:00:00 AM', 'Jan 1, 2014 12:00:00 AM', 81, 'USA', 'Other', Decimal('0.453014367308051'), 'Store floor')
:
:
```

シンプルなコードで Python から psycopg2 を使って Denodo に接続し、Excel ファイルのデータを取得 できました！

## おわりに

本記事では、Python から Denodo Platform のデータを扱う方法として、推奨されている **SQLAlchemy** と **psycopg2** を紹介しました。これらの方法を使うことで、通常のデータベースと同じ手順で Denodo に接続し、データを取得できることがわかったかと思います。

また、Denodo Platform に接続できるようになると、Denodo に統合された **すべてのデータソース** に対して、データの種類（データベース、Web サービス、Salesforce など）を意識せずに **統一的なクエリ** を実行できるようになります。  

これは非常に便利ですよね！

### もう少し詳しく知りたい方へ

弊社 **インサイトテクノロジー** は、Denodo 社のパートナーとして **Denodo Platform の紹介・販売・導入** を行っています。Denodo Platform にご興味のある方は、ぜひ弊社または Denodo 社までお問い合わせください。

https://www.insight-tec.com/products/denodo/

また、以下のような **データ統合の課題** をお持ちの方も、ぜひご相談ください。

- **データ統合基盤の構築をこれから進めたい**  
- **どのようにデータを統合すればよいか迷っている**  
- **既存のデータ統合環境を改善したい**（例: **Snowflake に SAP からリアルタイムデータを連携したい** など）

https://www.insight-tec.com/products/consulting/