Db2がベクトル検索にも対応したということで、connpassにイベントがあったのですが、スケジュール調整うまくいかず参加できませんでした😨 そこで、資料の公開もあったので、それをもとにテストしてみる環境をローカルで作ってみました。体験記というかよくわからない内容ですが、公開しておきます。
イベント情報
資料
私は、現在はFAISSやChromaDBをベクトルデータベースとして使用しています。RDBであるDb2はあまり得意ではないので抜けている情報もあると思います🙇
このエントリの内容について
今回動作させたアプリのバージョンなど
- Windows 11 + Docker Desktop 4.46.0 + Docker version 28.4.0
- WSL2 (Ubuntu 24.04) 今回はディストリビューション名を
Ubuntu 24.04からibmに変更しています。 - Python 3.12.3
- langchain-db2 (DB2VSクラス使用)
- sentence-transformers
実験環境の構成
Windows 11/10
├─ Docker Desktop(必須)
│ └─ WSL2統合を有効化 ← 「透過的に使える」設定
│
└─ WSL2 (Ubuntu推奨)
├─ Docker CLIコマンド → Windows側のDockerを呼び出し
├─ Python開発環境
│ ├─ uvまたはvenv
│ ├─ LangChain
│ └─ 開発スクリプト
│
└─ Dockerコンテナ(実際はWindows側で動作)
└─ Db2 with VECTOR support
└─ ポート: localhost:50000
詳細な接続フロー

- このエントリの内容について
- Docker Desktop WSL2統合設定(前提条件)
- 環境のセットアップ
- 実験用スクリプト
- 追加の実験用スクリプト
- 完成時のプロジェクト構成
- 環境の中断と再開について
- 実験の終了とクリーンアップ
- おわりに
Docker Desktop WSL2統合設定(前提条件)
ここで行っているのはWSL2の中でWindowsのDocker Desktopを透過的に使えるようにする設定です。この設定を行うことで、WSL内であたかもLinuxネイティブのDockerが入っているかのようにdockerコマンドが使えるようになります。実際にはWindows側のDocker Desktopが動いていますが、WSLからは意識する必要がありません。
Windows側での設定(最初に必ず実施)
Docker Desktopの確認
以下を実行しWindowsにDockerがインストールされていることを確認してください。
PS> docker --version

WSL2統合を有効化
1. Docker Desktopを起動
- WindowsスタートメニューからDocker Desktopを起動(またはシステムトレイのDockerアイコンが白くなるまで待つ)

2. 設定画面からWSL2統合を行う
Docker Desktop右上の ⚙(設定)アイコンをクリック(または、システムトレイのDockerアイコンを右クリック → 【Change Settings】)Settings画面に遷移するので、左メニュー【General】を選択し、

Use the WSL 2 based engineにチェックを入れます。(→ DockerエンジンをWSL2上で動作させる)

左メニュー「Resources」を選択し、【WSL Integration】タブをクリック、Enable integration with my default WSL distroにチェックを入れます。(→ WSL2内でdockerコマンドを使えるようにする)

同画面のEnable integration with additional distros(追加するのディストリビューション)で実験に使用するWSLディストリビューションをオンにします。個別指定してください。設定が終わったら「Apply & Restart」をクリックします。

これでWSL2内からWindows側のDockerを透過的に使えるようになります!
WSL2でDockerコマンドの確認
改めて、実験に使用するWSL2ディストリビューションを起動してdockerコマンドが使えることを確認します。
$ docker --version # 出力例: Docker version 28.4.0, build d8eb465

これで準備は事前完了です。
環境のセットアップ
以下の作業はWSL2の中で行います。
1. プロジェクトディレクトリ作成
まずはプロジェクト用のディレクトリを作成し、移動します。
$ mkdir ~/db2-vector-handson $ cd ~/db2-vector-handson
2. Db2のみDockerで起動
つづいて、DockerでDb2コンテナを起動します。今回はシンプルにDb2のみを起動します。 設定はdocker-compose.ymlに記述します。VSCodeなどのエディタを使用して作成してください。
docker-compose.yml
version: '3.8' services: db2: image: icr.io/db2_community/db2:latest container_name: db2-vector-handson privileged: true environment: - LICENSE=accept - DB2INSTANCE=db2inst1 - DB2INST1_PASSWORD=password - DBNAME=vectordb - ARCHIVE_LOGS=false - AUTOCONFIG=false ports: - "50000:50000" # WSLからアクセス可能 volumes: - db2-data:/database volumes: db2-data:

docker-compose.ymlを保存したら、以下のコマンドでDb2コンテナを起動します。起動には数分かかります。
Db2起動(バックグラウンド)
$ docker-compose up -d


これでDb2コンテナが起動しました。
Docker Desktopからもコンテナが起動していることがわかります。

3. Python環境構築
つづいてPython環境を構築します。今回はuvを使用して高速に仮想環境を作成し、必要なパッケージをインストールします。venvでも問題ありませんが、今回はインストールするパッケージが多いため、uvの方が圧倒的に速いのでおすすめします。
# uvインストール(まだの場合) $ curl -LsSf https://astral.sh/uv/install.sh | sh

uvのインストールが完了したら、仮想環境に入り、ライブラリをインストールしていきます。 uv addコマンドでのインストールでも問題はないですが、今回はpipを意識する形にしています。
# Python仮想環境作成
$ uv venv
$ source .venv/bin/activate
# 必要パッケージインストール(uvで高速ですがそれでも時間がかかります)
$ uv pip install \
langchain \
langchain-community \
langchain-huggingface \
langchain-db2 \
ibm-db \
ibm-db-sa \
sqlalchemy \
pandas \
sentence-transformers \
ipython

インストールが終わればいよいよ実験を進めることになります。
実験用スクリプト
動作実験用のスクリプトを3つ用意しました。各スクリプトは独立しており、順番に実行することでDb2のベクトル検索機能を体験できます。
- 接続テスト(test_connection.py)
- ベクトルテーブル作成(create_vector_table.py)
- 検索デモ(search_demo.py)
1. 接続テスト(test_connection.py)
このスクリプトはDb2コンテナが正常に起動し、接続可能な状態になっているかを確認します。 Dockerコンテナ起動直後はDb2の初期化に時間がかかるため、リトライ機能を実装しています。
test_connection.py
import ibm_db import time def test_connection(retry=5): """Db2接続テスト(リトライ付き)""" dsn = "DATABASE=vectordb;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;UID=db2inst1;PWD=password;" for i in range(retry): try: conn = ibm_db.connect(dsn, "", "") print(f"Db2接続成功!") # バージョン確認 stmt = ibm_db.exec_immediate(conn, "VALUES CURRENT SERVER") server = ibm_db.fetch_tuple(stmt) print(f"サーバー: {server[0]}") ibm_db.close(conn) return True except Exception as e: print(f"試行 {i+1}/{retry}: {e}") if i < retry - 1: print("30秒後に再試行...") time.sleep(30) return False if __name__ == "__main__": if test_connection(): print("\n接続確認完了") else: print("\n接続失敗。docker-compose ps で確認してください")

実行は以下のコマンドで行います。
$ python test_connection.py

ポイント
- DSN(Data Source Name)文字列にはDb2接続に必要なすべての情報が含まれています
VALUES CURRENT SERVERはDb2の特殊レジスタで、現在接続しているデータベース名を返します
2. ベクトルテーブル作成(create_vector_table.py)
サンプルデータを使ってベクトルテーブルを作成します。テキストデータを埋め込みモデルでベクトルに変換し、Db2のVECTORデータ型として保存します。
create_vector_table.py
import ibm_db import ibm_db_dbi from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document from langchain_db2 import DB2VS from langchain_community.vectorstores.utils import DistanceStrategy print("Db2ベクトルテーブル作成スクリプト") print("="*50) # 接続 dsn = "DATABASE=vectordb;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;UID=db2inst1;PWD=password;" conn = ibm_db.connect(dsn, "", "") connection = ibm_db_dbi.Connection(conn) print("Db2接続完了") # サンプルデータ products = [ {"name": "ThinkPad X1", "desc": "超軽量ノートPC 1.1kg", "price": 198000}, {"name": "MX Master 3", "desc": "高精度ワイヤレスマウス", "price": 13500}, {"name": "HHKB Pro", "desc": "プログラマー向けキーボード", "price": 35000}, {"name": "4Kモニター", "desc": "27インチ高解像度ディスプレイ", "price": 78000}, {"name": "Webカメラ", "desc": "1080p高画質ビデオ会議用", "price": 8000}, ] # Document作成 docs = [] for p in products: doc = Document( page_content=f"{p['name']}: {p['desc']} (¥{p['price']:,})", metadata={"name": p['name'], "price": p['price']} ) docs.append(doc) print(f"{len(docs)}件のドキュメント準備完了") # 埋め込みモデル print("埋め込みモデル準備中...") embeddings = HuggingFaceEmbeddings( model_name="sentence-transformers/all-MiniLM-L6-v2" ) # Db2ベクトルストア作成 print("Db2にVECTORテーブル作成中...") vector_store = DB2VS.from_documents( documents=docs, embedding=embeddings, client=connection, # clientパラメータを使用 table_name="PRODUCTS", distance_strategy=DistanceStrategy.COSINE ) print("完了!テーブル: PRODUCTS") # グローバル変数として保存(対話的実行用) globals()['vector_store'] = vector_store globals()['connection'] = connection

実行は以下のコマンドで行います。このスクリプトを実行すると、PRODUCTSという名前のベクトルテーブルが作成され、サンプルデータが登録されます。⚠️初回は埋め込みモデルのダウンロードに時間がかかります。
$ python create_vector_table.py

ポイント
sentence-transformers/all-MiniLM-L6-v2モデルは384次元のベクトルを生成します(初回実行時に自動ダウンロード、約80MB)page_contentがベクトル化される対象で、metadataは検索時のフィルタリングに使用されますDistanceStrategy.COSINEを指定することで、テキストの意味的類似性に適したコサイン類似度を使用しますfrom_documentsメソッドは既存テーブルを削除して新規作成するため、追記したい場合はadd_documentsを使用します(何度実行しても大丈夫です)
3. 検索デモ(search_demo.py)
作成したベクトルテーブルに対して類似検索を実行し、結果を人間に分かりやすい形式で表示します。関連度%の計算方法も含まれています。
search_demo.py
import ibm_db import ibm_db_dbi from langchain_huggingface import HuggingFaceEmbeddings from langchain_db2 import DB2VS from langchain_community.vectorstores.utils import DistanceStrategy # 接続とストア初期化 dsn = "DATABASE=vectordb;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;UID=db2inst1;PWD=password;" conn = ibm_db.connect(dsn, "", "") connection = ibm_db_dbi.Connection(conn) embeddings = HuggingFaceEmbeddings( model_name="sentence-transformers/all-MiniLM-L6-v2" ) vector_store = DB2VS( embedding_function=embeddings, client=connection, # clientパラメータ table_name="PRODUCTS", distance_strategy=DistanceStrategy.COSINE ) def search(query, k=3): """ ベクトル類似検索を実行し、結果を表示 関連度%の計算方法: - similarity_search_with_scoreはコサイン距離(0〜2)を返す - コサイン距離 = 1 - コサイン類似度 - 距離0 = 完全一致、距離1 = 無関係 - 関連度% = (1 - 距離) × 100 例:距離0.3の場合 → 関連度70% """ print(f"\n検索: 「{query}」") results = vector_store.similarity_search_with_score(query, k=k) for i, (doc, score) in enumerate(results, 1): print(f"{i}. {doc.metadata['name']}") # scoreはコサイン距離(0に近いほど類似) # これを人間に分かりやすい%に変換 print(f" 関連度: {(1-score)*100:.1f}%") print(f" 内容: {doc.page_content}") return results # テスト検索 if __name__ == "__main__": search("プログラミング") search("ビデオ会議")

実行は以下のコマンドで行います。また、対話モード(-i オプション)で実行することで、スクリプト実行後もPython環境に留まり、追加の検索を試行できます。
$ python search_demo.py

# 対話モードで実行(実行後も試行できます) $ python -i search_demo.py

ポイント
関連度%の計算について
- Db2の
VECTOR_DISTANCE関数(COSINE指定時)が返す値は「コサイン距離」です - コサイン距離は0(完全一致)から2(正反対)の範囲を取ります
- 実用的には0〜1の範囲がよく使われます(垂直以下の角度)
(1-score)*100の変換により、直感的な「マッチ度」として表示できます
検索の仕組み
対話モードの利点
追加の実験用スクリプト
ベクトルテーブルの構造確認や、対話的にデータ追加できるスクリプトになります。
1. テーブル確認(check_table.py)
Db2のシステムカタログをクエリして、作成されたベクトルテーブルの構造を確認します。 VECTORデータ型が正しく作成されているか、メタデータがどのように格納されているかを可視化できます。
check_table.py
import ibm_db dsn = "DATABASE=vectordb;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;UID=db2inst1;PWD=password;" conn = ibm_db.connect(dsn, "", "") # テーブル一覧 sql = """ SELECT TABNAME, COLCOUNT FROM SYSCAT.TABLES WHERE TABSCHEMA = CURRENT SCHEMA AND TYPE = 'T' """ stmt = ibm_db.exec_immediate(conn, sql) print("テーブル一覧:") while ibm_db.fetch_row(stmt): name = ibm_db.result(stmt, 0) cols = ibm_db.result(stmt, 1) print(f" - {name} ({cols}列)") # PRODUCTS テーブルの構造 sql = """ SELECT COLNAME, TYPENAME, LENGTH FROM SYSCAT.COLUMNS WHERE TABNAME = 'PRODUCTS' AND TABSCHEMA = CURRENT SCHEMA """ stmt = ibm_db.exec_immediate(conn, sql) print("\nPRODUCTS テーブル構造:") while ibm_db.fetch_row(stmt): col = ibm_db.result(stmt, 0) typ = ibm_db.result(stmt, 1) length = ibm_db.result(stmt, 2) if typ == "VECTOR": print(f" - {col}: {typ}({length})") # VECTORデータ型! else: print(f" - {col}: {typ}") ibm_db.close(conn)

実行は以下のコマンドで行います。
$ python check_table.py

ポイント
SYSCAT.TABLESとSYSCAT.COLUMNSはDb2のシステムカタログビューで、データベースのメタデータを格納しています- VECTORデータ型の場合、LENGTHフィールドには次元数×要素サイズ(FLOAT32なら4バイト)が格納されます
期待される出力例
テーブル一覧: - PRODUCTS (4列) PRODUCTS テーブル構造: - EMBEDDING: VECTOR(384) - ID: CHARACTER - METADATA: BLOB - TEXT: CLOB
2. データ追加スクリプト(add_data.py)
対話的に新しい商品データを追加します。 既存のテーブルに影響を与えずに、新しいレコードのみを追加します。追加後すぐに検索で確認もできます。
add_data.py
import sys import ibm_db import ibm_db_dbi from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document from langchain_db2 import DB2VS from langchain_community.vectorstores.utils import DistanceStrategy # 接続 dsn = "DATABASE=vectordb;HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;UID=db2inst1;PWD=password;" conn = ibm_db.connect(dsn, "", "") connection = ibm_db_dbi.Connection(conn) embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2") vector_store = DB2VS( embedding_function=embeddings, client=connection, # clientパラメータ table_name="PRODUCTS", distance_strategy=DistanceStrategy.COSINE ) print("商品追加ツール") print("-" * 30) name = input("商品名: ") desc = input("説明: ") price = int(input("価格: ")) # Documentオブジェクトを作成 # page_contentがベクトル化される内容 # metadataは検索時のフィルタリングに使用 doc = Document( page_content=f"{name}: {desc} (¥{price:,})", metadata={"name": name, "price": price} ) # add_documentsメソッドは既存データを削除せずに追記 vector_store.add_documents([doc]) print(f"追加完了: {name}") # 確認検索 print("\n確認検索:") # 追加した商品名で検索して、正しく登録されたか確認 results = vector_store.similarity_search(name, k=1) if results: print(f"→ {results[0].page_content}")

実行は以下のコマンドで行います。
$ python add_data.py

ポイント
add_documents()メソッドは既存データを保持したまま新規データを追加します(from_documents()とは異なる)- 追加したデータは即座に検索可能になります(トランザクションがコミットされるため)
使用例
商品追加ツール ------------------------------ 商品名: Surface Pro 説明: 2in1タブレットPC 価格: 150000 追加完了: Surface Pro 確認検索: → Surface Pro: 2in1タブレットPC (¥150,000)
このスクリプトを使って様々な商品を追加し、その後search_demo.pyで検索することで、ベクトル検索がどのように意味を理解しているかを実験できます。例えば「タブレット」で検索すると「Surface Pro」がヒットするなど、キーワードの完全一致ではなく意味的な類似性で検索されることが確認できます。

完成時のプロジェクト構成
作業が完了すると、以下のようなファイル構成になっています。
~/db2-vector-handson/ ├── docker-compose.yml # Db2コンテナ設定 ├── .venv/ # Python仮想環境(uv作成) │ ├── bin/ │ ├── lib/ │ └── ... ├── create_vector_table.py # ベクトルテーブル作成 ├── test_connection.py # 接続テスト ├── search_demo.py # 検索デモ ├── add_data.py # データ追加ツール └── check_table.py # テーブル構造確認
環境の中断と再開について
⚠️今回のDB2コンテナは初期化の安定性を考慮し、毎回クリーンな状態から起動する方針、つまりコンテナを停止してデータの永続化は行なわないことにします。
実験の中断の手順
以下の手順で中断と再開が可能です。
# 中断する場合 $ deactivate # Python仮想環境終了 $ docker-compose down -v # Db2コンテナ停止(ボリュームも削除) # 再開する場合 $ docker-compose up -d # 接続確認 $ docker exec db2-vector-handson su - db2inst1 -c "db2 connect to vectordb"
データベース作成エラーの対処法
実は中断から再開の手順を行い、コンテナは起動してもデータベース作成でエラーになることがあります。 以下のようなエラーが表示された場合には、手動でデータベースを作成してください。
SQL1013N The database alias name or database name "VECTORDB" could not be found.
または
SQL1031N The database directory cannot be found on the indicated file system.
手動でデータベースを作成方法
以下のコマンドを行うことで、手動でデータベースを作成できます。
# vectordbを手動作成 $ docker exec db2-vector-handson su - db2inst1 -c "db2 create database vectordb"
作成に成功すると、以下のようなメッセージが表示されます。
DB20000I The CREATE DATABASE command completed successfully.

⚠️手動の作成も1回で成功しないこともあるため、以下のメッセージが出るまで何度か実行してください。
成功後、接続確認を行います。
$ docker exec db2-vector-handson su - db2inst1 -c "db2 connect to vectordb"
以下のような表示が出れば実験開始可能できます。
Database Connection Information Database server = DB2/LINUXX8664 12.1.2.0 SQL authorization ID = DB2INST1 Local database alias = VECTORDB
実験の終了とクリーンアップ
実験を終了する際は、使用したリソースを適切にクリーンアップしましょう。
完全なクリーンアップ(すべて削除)
実験を完全に終了し、すべてのリソースを削除する場合:
# 1. Python仮想環境を終了 $ deactivate # 2. Dockerコンテナとボリュームを削除 $ cd ~/db2-vector-handson $ docker-compose down -v # 3. コンテナとボリュームが削除されたことを確認(何も表示されないことを確認) $ docker ps -a | grep db2-vector-handson $ docker volume ls | grep db2-vector-handson # 4. プロジェクトディレクトリ全体を削除 $ cd ~ $ rm -rf db2-vector-handson # 5. (オプション)Dockerイメージも削除する場合 docker images | grep db2_community # イメージIDを確認して削除 docker rmi icr.io/db2_community/db2:latest
おわりに
Db2のベクトル検索機能をローカル環境で試すための手順を実験してみました。DockerとWSL2を組み合わせることで、手軽にDb2の最新機能を体験できます。
最近のRDBはベクトルデータも扱えるようになってるんですねちょっと驚きました。FAISSやChromaDBのような専用ベクトルDBと比べると、割と大規模感があるので、用途によって使い分けるのがいいのかもしれません。