概要
Vector databaseの1つであるQdrantを利用するにあたって、その内部構造を理解する必要があると感じたので、調査した内容を記載します。
Qdrantの全体像
こちらの絵が非常にわかりやすいです。
詳細な説明は公式ドキュメントに譲りますが、重要だと感じた要素を簡単に整理します。
用語 | 意味 |
---|---|
Collection | RDBにおけるテーブルに相当する概念。Pointの集合 |
Point | RDBにおけるレコードに相当する概念。Id,Vector,Payloadで構成される |
Id | 一意の識別子 |
Vector | 画像、音声、ドキュメント、ビデオなどのデータの高次元表現 |
Payload | Vectorに追加されたJSON形式のデータ |
Payload
を用いて類似性検索時にフィルタリングできるというのが、Qdrantの特徴のようです。
また、ストレージの仕組みについては2つの方式があるようです。
用語 | 意味 |
---|---|
In-memory | Vectorをメモリに格納する方式。高速 |
Memmap | Vectorをディスクに格納する方式。ディスク上のファイルを、仮想メモリのアドレス空間にマッピングする。十分なメモリがあれば、In-memoryと同じくらい高速。Qdrantマシンが高速なディスクで稼働し、大規模なCollectionを扱う場合に推奨される方式 |
次に、CollectionやPointの中身を実際に触ってみようと思います。
私はpythonに明るくないため、curlで操作します。
環境
下記のバージョンで確認をしました。
Qdrant 1.9.4
Docker 24.0.5
WSL2 Ubuntu 22.04 on Windows
Qdrantインストール
インストール方法はこちらを参照してください。
私は今回、Dockerでインストールしました。
$ docker run -d -p 6333:6333 \
-v $(pwd)/path/to/data:/qdrant/storage \
qdrant/qdrant
Collection作成、確認
QdrantのAPIドキュメントにサンプルが載っていたので利用させていただきます。
test_collection
という名前のCollectionを作成します。
今回は指定していませんが、"on_disk": true
と設定することで、前述のMemmap利用モードになるようです。
詳細はこちらをご確認下さい。
$ curl -X PUT 'http://localhost:6333/collections/test_collection' \
-H 'Content-Type: application/json' \
--data-raw '{
"vectors": {
"size": 4,
"distance": "Dot"
}
}'
QdrantはWebUI機能も備えており、ブラウザから下記のURLでダッシュボード画面にアクセスできます。ダッシュボード画面から、Qdrantに登録したデータが閲覧可能なため、実運用の際には6333 Portを外部公開しないなど、慎重に取り扱う必要がありそうです。
http://localhost:6333/dashboard
ダッシュボードを開くと、test_collection
が作成されていることが確認できます。
curlで確認することも可能です。次のコマンドではCollectionの一覧を取得しています。
$ curl -X GET "http://localhost:6333/collections" -H "Content-Type: application/json"
{"result":{"collections":[{"name":"test_collection"}]},"status":"ok","time":4.5e-6}
次のコマンドでは、作成したtest_collection
の詳細情報を取得しています。
$ curl -X GET "http://localhost:6333/collections/test_collection" -H "Content-Type: application/json"
{"result":{"status":"green","optimizer_status":"ok","indexed_vectors_count":0,"points_count":0,"segments_count":8,"config":{"params":{"vectors":{"size":4,"distance":"Dot"},"shard_number":1,"replication_factor":1,"write_consistency_factor":1,"on_disk_payload":true},"hnsw_config":{"m":16,"ef_construct":100,"full_scan_threshold":10000,"max_indexing_threads":0,"on_disk":false},"optimizer_config":{"deleted_threshold":0.2,"vacuum_min_vector_number":1000,"default_segment_number":0,"max_segment_size":null,"memmap_threshold":null,"indexing_threshold":20000,"flush_interval_sec":5,"max_optimization_threads":null},"wal_config":{"wal_capacity_mb":32,"wal_segments_ahead":0},"quantization_config":null},"payload_schema":{}},"status":"ok","time":0.0000653}
Point作成、確認
こちらもサンプルがあったので利用させていただきます。Pointを6つPUTしてみます。
コマンドを見ると、Pointは以下の3つの要素から構成されていることが確かに分かります。
・id
・vector
・payLoad
$ curl -L -X PUT 'http://localhost:6333/collections/test_collection/points?wait=true' \
-H 'Content-Type: application/json'\
--data-raw '{
"points": [
{"id": 1, "vector": [0.05, 0.61, 0.76, 0.74], "payload": {"city": "Berlin"}},
{"id": 2, "vector": [0.19, 0.81, 0.75, 0.11], "payload": {"city": ["Berlin", "London"] }},
{"id": 3, "vector": [0.36, 0.55, 0.47, 0.94], "payload": {"city": ["Berlin", "Moscow"] }},
{"id": 4, "vector": [0.18, 0.01, 0.85, 0.80], "payload": {"city": ["London", "Moscow"] }},
{"id": 5, "vector": [0.24, 0.18, 0.22, 0.44], "payload": {"count": [0]}},
{"id": 6, "vector": [0.35, 0.08, 0.11, 0.44]}
]
}'
{"result":{"operation_id":0,"status":"completed"},"status":"ok","time":0.011843266}
WebUIから、Pointが作成されていることが確認できます。
curlでの確認結果は次の通りです。id 1
のPoint情報を取得しています。
$ curl -X GET "http://localhost:6333/collections/test_collection/points/1" -H "Content-Type: application/json"
{"result":{"id":1,"payload":{"city":"Berlin"},"vector":[0.05,0.61,0.76,0.74]},"status":"ok","time":0.0001196}
【おまけ】類似性検索
Pointを登録できたので、最後に類似性検索をしてみます。
Vectorとして[0.2,0.1,0.9,0.7]を与え、Top3を検索します。
$ curl -L -X POST 'http://localhost:6333/collections/test_collection/points/search' \
-H 'Content-Type: application/json' \
--data-raw '{
"vector": [0.2,0.1,0.9,0.7],
"with_vectors": true,
"with_payload": true,
"top": 3
}'
{"result":[{"id":4,"version":0,"score":1.362,"payload":{"city":["London","Moscow"]},"vector":[0.18,0.01,0.85,0.8],"order_value":null},{"id":1,"version":0,"score":1.273,"payload":{"city":"Berlin"},"vector":[0.05,0.61,0.76,0.74],"order_value":null},{"id":3,"version":0,"score":1.208,"payload":{"city":["Berlin","Moscow"]},"vector":[0.36,0.55,0.47,0.94],"order_value":null}],"status":"ok","time":0.0021894}
scoreが高い順に
id 4
id 1
id 3
の3件がヒットすることを確認できました。
所感
手を動かすことで、ぼんやりとしていたQdrantに対する理解は、ある程度深まったと思います。
参考
https://qdrant.tech/documentation/overview/
https://qdrant.tech/documentation/concepts/storage/
https://qdrant.tech/documentation/concepts/payload/
https://qdrant.github.io/qdrant/redoc/index.html
https://qdrant.tech/documentation/concepts/search/#payload-and-vector-in-the-result