Rust製のベクトルデータベースQdrantを試してみる
どうも!オペレーション部の西村祐二です。
ChatGPT関連の専用アプリケーションを作成しようとすると、「ベクトルデータベース」という用語が出てきます。これは私にとって、これまでまったく経験したことのない分野で理解できていない状態でした。
このままでは行き詰まってしまうという思いと、この分野に関してある程度知識を身につけておくと、今後応用がききそうだなと考えました。
そこで今回、他のベクトルデータベースと比べて機能がシンプルそうで、Rustで作られているという特徴から、Qdrantを試してみました。
Qdrantとは
公式ドキュメントから引用し翻訳したもの
Qdrantは「ベクトルの類似性検索エンジンであり、追加のペイロード(つまりベクトル)を格納、検索、管理するための便利なAPIを備えた本番環境で使用できるサービスを提供します。」ペイロードとは、検索を絞り込むのに役立つ追加の情報や、ユーザーに提供できる有用な情報と考えることができます。
Qdrantのアーキテクチャの概要
用語
Qdrant内で利用される用語ではじめに知っておくと良い最低限の用語をまとめておきます。
なるべく簡潔に記載しているので、正確ではないかもしれません。正確な情報を知りたい場合はドキュメントを確認ください。
Collections
Pointの集合。テーブルのようなもの。
Points
id、ベクトルデータ、Payloadで構成されるデータの塊。レコードのようなもの。
Payload
ベクトルデータに追加できる付加情報。JSONで管理される。
試してみる
Qdrantを起動
QdrantはOSSでDockerを使ってローカルで試すことができます。
$ docker pull qdrant/qdrant
Docker 内でサービスを実行します
docker run -p 6333:6333 \ -v $(pwd)/qdrant_storage:/qdrant/storage \ qdrant/qdrant
起動したらlocalhost:6333
にアクセスすると下記のような表示になるかと思います。
{"title":"qdrant - vector search engine","version":"1.1.3"}
Pythonのクライアントを使って操作する
Python以外にもRust、Go、Javascriptなどのクライアントライブラリがあります。
$ pip install qdrant-client
Collectionを作成
はじめにCollectionを作成します。名前は「test_collection」としておきます。
ベクトル間の類似性を測定するために利用されるメトリクスとして、現在3つサポートされています。今回は「Dot product」を設定しています。
- Dot product
- Cosine similarity
- Euclidean distance
from qdrant_client import QdrantClient from qdrant_client.http.models import Distance, VectorParams client = QdrantClient("localhost", port=6333) client.recreate_collection( collection_name="test_collection", vectors_config=VectorParams(size=4, distance=Distance.DOT), )
作成したCollectionの状態を下記で取得することができます。
collection_info = client.get_collection(collection_name="test_collection") print(collection_info)
Pointを追加
都市の情報やcountの情報をPayloadとしてもつベクトルデータを登録します。
from qdrant_client import QdrantClient from qdrant_client.http.models import PointStruct client = QdrantClient(host="localhost", port=6333) operation_info = client.upsert( collection_name="test_collection", points=[ PointStruct(id=1, vector=[0.05, 0.61, 0.76, 0.74], payload={"city": "Berlin"}), PointStruct(id=2, vector=[0.19, 0.81, 0.75, 0.11], payload={"city": ["Berlin", "London"]}), PointStruct(id=3, vector=[0.36, 0.55, 0.47, 0.94], payload={"city": ["Berlin", "Moscow"]}), PointStruct(id=4, vector=[0.18, 0.01, 0.85, 0.80], payload={"city": ["London", "Moscow"]}), PointStruct(id=5, vector=[0.24, 0.18, 0.22, 0.44], payload={"count": [0]}), PointStruct(id=6, vector=[0.35, 0.08, 0.11, 0.44]), ] ) print(operation_info)
実行結果
operation_id=1 status=<UpdateStatus.COMPLETED: 'completed'>
Pointを取得
登録したPointをidをつかって取得することができます。
points = client.retrieve( collection_name="test_collection", ids=[1,2,3], ) print(points)
実行結果
[Record(id=3, payload={'city': ['Berlin', 'Moscow']}, vector=None), Record(id=1, payload={'city': 'Berlin'}, vector=None), Record(id=2, payload={'city': ['Berlin', 'London']}, vector=None)]
Pointを検索
- ベクトルの情報を使って検索することができます。
from qdrant_client import QdrantClient client = QdrantClient(host="localhost", port=6333) search_result = client.search( collection_name="test_collection", query_vector=[0.2, 0.1, 0.9, 0.7], limit=3 ) print(search_result)
実行結果
スコアの情報が含まれており、検索に利用したベクトルデータと近いPointが上位3つ選択されたことがわかります。
[ScoredPoint(id=4, version=1, score=1.362, payload={'city': ['London', 'Moscow']}, vector=None), ScoredPoint(id=1, version=1, score=1.273, payload={'city': 'Berlin'}, vector=None), ScoredPoint(id=3, version=1, score=1.208, payload={'city': ['Berlin', 'Moscow']}, vector=None)]
- Filterを使って検索することができます。
ベクトルだけではなく、Payloadに対してフィルタリングするこができます。複雑なフィルタリングがサポートされてます。
このFilter機能がおそらくQdrantの強みになってくるのかなと思います。
下記では、payloadに「city」があり、値が「London」のものだけにフィルターしています。
from qdrant_client.http.models import Filter, FieldCondition, MatchValue from qdrant_client import QdrantClient client = QdrantClient(host="localhost", port=6333) search_result = client.search( collection_name="test_collection", query_vector=[0.2, 0.1, 0.9, 0.7], query_filter=Filter( must=[ FieldCondition( key="city", match=MatchValue(value="London") ) ] ), limit=3 ) print(search_result)
実行結果
[ScoredPoint(id=4, version=1, score=1.362, payload={'city': ['London', 'Moscow']}, vector=None), ScoredPoint(id=2, version=1, score=0.871, payload={'city': ['Berlin', 'London']}, vector=None)]
さいごに
今回、Rust製のベクトルデータベースQdrantを試してみました。
Dockerを使ってローカルからサクッと試せてかなりお手軽でした。
操作もシンプルで理解しやすいので、ベクトルデータベースが気になってる人のはじめの一歩として良いのではないかなと思いました。
今後は他の関連ツールと組み合わせて試していきたいと思います。
誰かの参考になれば幸いです。