ベクトル検索エンジンQdrantの紹介

2022/12/14に公開

はじめに

これはLivesense Advent Calendar 2022 DAY 14 の記事です。

普段は主にレコメンドシステムの開発・運用をやっています。仕事ではPythonを書くことが多いです。好きな言語はRustです。この記事では、ベクトル検索エンジンQdrantを紹介します。

ベクトル検索とは

そもそもベクトル検索とは何だ、という人もいると思います。簡単に言えばベクトル検索は類似するベクトルを(正確性を犠牲にして)高速に計算する技術です。

なぜそのような技術が必要になるのか簡単に説明しましょう。

なぜベクトルの類似度を計算する必要があるのか

近年、機械学習技術によって様々なものがベクトルで表現されるようになりました。典型的には画像と文書(単語)です。

「類似する画像を求める」「ユーザーが入力したワードに関連する文書を返す」「ユーザーが閲覧したアイテムに類似するアイテムのリストを作成する」これらはすべて対象物がベクトルで表現されていれば、ベクトル同士の類似度を計算するタスクに置き換えることができます。

ベクトルの類似度はコサイン類似度などで測られます。

\text{cos}(\bold{a}, \bold{b}) = \frac{\bold{a}\cdot \bold{b}}{\|\bold{a}\|\|\bold{b}\|}

角度が0のときコサインは1、直角のとき0、逆方向のときは-1になります。同じ方向を向いていれば類似しているということです。

なぜ正確性を犠牲にするのか

厳密解は計算量が多くなるからです。

すでにベクトル化された画像や文書の集合があるとしましょう。与えられたベクトルに対し、正確に類似するベクトルを求めるにはすべての候補について類似度を計算する必要があります。画像が100万枚あって、入力画像にもっとも類似するものtop10が知りたい、という場合100万回計算する必要があります。

この計算に工夫の余地は少なく、候補の規模が大きくなるとシンプルに時間がかかるようになります。一方で検索やレコメンドの文脈では完全なリストを提示するよりも、高速にレスポンスすることのほうが重要であることも少なくありません。そこで多少の正確性を犠牲にして、高速に計算するアルゴリズムが開発されており、それがベクトル検索というわけです。

ベクトル検索のアルゴリズム

ベクトル検索(あるいは近似近傍検索)にはいくつかのアルゴリズムがあります。どのようなアルゴリズムがあり、どのように発展してきたかこちらに詳しくまとまっています。現在多くのライブラリで実装されている代表的なアルゴリズムはHNSW(Hierachical Navigable Small World)と言って良いでしょう。HNSWの詳細が知りたい方は論文を読んでみてください。

HNSWはfaissや最近ではElasticsearchでも利用できます。今回紹介するQdrantでもHNSWがベクトル検索のアルゴリズムとして実装されています。

Qdrantについて

Qdrant(クワドラントと読みます)はQdrant社が開発しているベクトル検索エンジンです。SaaS版もありますが、ここでは自前でホストする前提で説明します。すでに書いたとおり、Qdrantはベクトルの近似近傍検索を利用した類似ベクトルの検索や類似度に基づくランキングの作成を高速に実行できます。

Qdrantの良いところ

1 簡単に試すことができる

公式のdocker imageがあり簡単に試すことができます。

docker pull qdrant/qdrant
docker run -p 6333:6333 qdrant/qdrant

これでqdrantサーバーをローカルに起動し、データを投入できるようになります。

2 フィルタリングできる

Qdrantにはフィルタリング機能があります。

フィルタリングとはレコメンドにおいて、アイテムの属性に基づいて結果を絞り込む処理のことです。例えば、求人のレコメンドであれば、東京在住のユーザーには東京近辺の求人を提示したいわけです。そこでレコメンドモデルが出力した結果から条件に合うもののみリストアップして提示するということは、よく行われます。

レコメンドシステムを実装する上ではほぼ必須と言って良いフィルタリング機能ですが、ベクトル検索用のライブラリやアプリケーションがこうした機能を備えているとは限りません(例えば、faissにはフィルタリング機能はありません)。

2-1 複雑なフィルタリングも実現できる

ドキュメントをみるとわかるとおり、フィルタリングのために以下のような述語が用意されています。

  • Must
  • Should
  • Must Not
  • ...

このような述語を組み合わせ、例えば

((所在地が東京都または神奈川県)かつ(年収500万円以上))または(リモートワーク可)

のような条件で求人の検索結果を絞り込むようなクエリを生成することもできます。

2-2 フィルタリングとHNSWを併用するための特別なチューニングを実施している

HNSWはフィルタリングと併用すると精度が極端に悪化することがあります。Qdrantはこの問題を回避するために、フィルタリングに使用する属性に基づくエッジをグラフに追加するという方法で、アルゴリズムをチューニングしてます。詳しくはドキュメントブログで説明されています。

3 Rust製である

Rust製であることを持ってQdrantは良い! と言って良いかどうかはなんとも言えませんが、いいですよね、Rust。

なお、クライアントはRustの他にPythonとGoがあります。

Qdrantの気になるところ

Qdrantを試してみて気になったところもありました。それは個別のフィルタリングを実行するとパフォーマンスが悪化するところです。

バッチ処理のレコメンドではユーザーごとに異なるフィルタリング条件でアイテムを問い合わせるということがよくあると思います。メルマガでユーザーに提示するアイテムをまとめて計算する時などです。このようなシナリオではQdrantは急速にレスポンスが悪化することがあります。

リアルタイムのレコメンドや検索用途であれば問題なく使用できるはずなので、要件しだいですね。

まとめ

Qdrantという名前を初めて聞いたという方もいることと思います。簡単に利用できて高機能ですので、試してみてはいかがでしょうか。

Discussion