コンテンツにスキップ

ベクトル検索を試し、見つけた問題をOSS本家へ返す

ベクトル検索の研究やPloneへの組み込みを進める中で、Lance、SQLite vec1、LanceDBの動作について、本家への不具合報告や修正提案を行いました。修正がリリースされたものもあれば、修正案の確認が進んでいるものもあります。今回は、それぞれの問題に気付いた経緯と、報告までに確かめたことを紹介します。

新しい実装をすぐに試せる環境

今年1月から、近似最近傍探索(ANN)やベクトル検索、Embeddingモデルの研究を続けています。データや実験コードを手元に置き、新しい手法やデータベースに興味を持ったら、すぐにテストできる環境を維持しています。実験をNotebookに積み重ねる取り組みも、その土台です。

LanceDBは実験に使うだけでなく、Ploneへの組み込みと画像検索のデモへと利用が広がりました。SQLiteのソースツリーに加わったベクトル検索拡張vec1も、性能や利用場面を見極めるために試しています。

こうして使う中で、検索結果や設定に、想定と異なる動作が見つかりました。

Lance:更新前のラベルで検索にヒットする

PloneへのLanceDB組み込みでは、メタデータで検索結果を絞り込んでいます。そこで、行のラベルを変更した後、インデックスを最適化すると、古いラベルの条件でもその行が検索にヒットする問題を見つけました。

調べると、大量のデータは必要なく、2行だけで再現できました。インデックスを使う場合と使わない場合を比較し、Lanceのラベル用インデックスの更新処理に原因を絞りました。修正と回帰テストをPR #9352として提出し、マージ後、Lance v13.0.0に含まれました。

詳しい経緯は10月8日の記事で紹介しています。検索機能を組み込む過程で、データ更新後の正しさまで確認したことが、修正につながった例です。

SQLite vec1:精度の低下を索引作成の問題まで絞る

vec1では、二値量子化(BQ)とコサイン距離を組み合わせ、既存データから索引を再構築する条件で、検索精度が大きく下がりました。同じデータでも、以前のバージョンや設定を変えた場合には、この低下が起きません。

そこで、バージョンと設定を比較し、さらに学習・索引作成・検索を分けて試しました。古いバージョンで作った索引を新しいバージョンで検索すると正常で、新しいバージョンで再構築した索引では問題が起きます。空の索引に後からデータを追加する場合も正常でした。この比較から、既存データをまとめて符号化する再構築処理に問題を絞り込めました。

再現コードと調査結果をフォーラムに投稿したところ、10月18日の再投稿と同日に、開発者から修正の返信がありました。修正はSQLiteの開発版に反映されています。

精度の数字だけでは、方式の特性なのか、実装の不具合なのかを判断できません。条件を一つずつ変え、どの処理から結果が変わるかを確認することが役に立ちました。

LanceDB:量子化の既定値を確認する

LanceDBでは、IVF_RQというベクトル索引を試す中で、量子化に使うビット数の既定値が気になりました。基盤のLanceでは5ビットになっている一方、LanceDBのPython APIでは1ビットが明示的に設定されていたためです。

ビット数は、検索精度と索引サイズに関わる設定です。比較実験でも実運用でも、指定を省略したときに何が選ばれるかを把握する必要があります。互換性のための意図的な設定なのかも含め、Issue #4582で確認を依頼しました。

10月19日時点では、LanceDB側で、ビット数を指定しなければLanceの既定値を引き継ぐ修正PR #4585が作られています。まだマージ前で、対応が進んでいる段階です。

実験と実装を行き来する

モデルや検索方式を比較する研究と、アプリケーションに組み込んで使う作業。それぞれで得た知識が、検索精度の変化や更新後の動作を調べるときにも役立っています。

再現できる形で問題を共有すると、本家の開発者と同じ現象を見ながら話を進められます。報告やPRを確認し、修正に対応してくださった開発者の皆さんに感謝しています。ベクトル検索の研究と実装を続けながら、見つけた問題や改善案を、使っているOSSにも返していきます。