SQLite公式のベクトル検索拡張「vec1」とは — IVFADC+OPQの仕組みと使い方、sqlite-vecとの違い
はじめに
SQLite の公式ソースツリーに、ベクトル検索の拡張機能「vec1」が入りました。mattn 氏の紹介記事によると、2026年9月30日に ext/vec1/ として取り込まれています。本体は約13,000行の vec1.c で、テストが50ファイル・約6,700行ついています。
これまで SQLite でベクトル検索をするには、sqlite-vec のようなサードパーティ製の拡張を使うのが普通でした。SQLite の開発元が自分たちで作った拡張が出てきたことで、選択肢が変わります。
この記事では、vec1 で何ができるのか、内部でどんな検索をしているのかを説明します。そのうえで、今すぐ使ってよいのか、どんな場面で効いてくるのかを考えます。
vec1 でできること
vec1 は、SQLite の仮想テーブルの仕組みを使って「近いベクトルを探す」機能を足す拡張です。公式ドキュメントに書かれている主な仕様は次のとおりです。
| 項目 | 内容 |
|---|---|
| 距離 | L2(ユークリッド距離)、コサイン距離 |
| インデックス | none(既定)/ flat(全件比較)、IVFADC + 量子化(近似検索) |
| 量子化 | pq / opq / bq(バイナリ量子化) / none |
| ベクトルの型 | 32ビット浮動小数点の BLOB(すべて同じ次元) |
| 高速化 | x86 は AVX2、ARM は NEON |
| 依存 | なし(C のファイル1つ) |
使い方は SQL だけで完結します。まず仮想テーブルを作り、rebuild コマンドでインデックスの種類と距離を指定します。
CREATE VIRTUAL TABLE v USING vec1;
INSERT INTO v(cmd, arg) VALUES('rebuild', '{index:"flat", distance:"l2"}');
INSERT INTO v(rowid, vector) VALUES
(1, vec1_from_json('[0,0,0,0]')),
(2, vec1_from_json('[1,1,1,1]')),
(3, vec1_from_json('[5,5,5,5]'));
SELECT rowid, distance FROM v(vec1_from_json('[0.9,1,1.1,1]'), '{K:2}');
検索はテーブル値関数の形で書きます。探したいベクトルと、何件返すか(K)を渡すだけです。JSON の配列を vec1_from_json() で BLOB に変換して入れます。なお、L2 で返る distance は二乗した距離です。
便利なのはメタデータ列です。仮想テーブルを vec1(vector, in_stock, price) のように作ると、WHERE in_stock = 1 AND price < 20000 のような条件をインデックスの中で評価できます。ただしインデックスの中で評価されるのは、AND でつないだ条件のうち、メタデータ列を < > = >= <= IS(IS NULL / IS NOT NULL を含む)で比べるものだけです。
配布の形にも注意が必要です。vec1 は SQLite を1ファイルにまとめた amalgamation(sqlite3.c)には含まれず、別に読み込むローダブル拡張として配られます。SQLite を最新にすれば自動で使えるわけではありません。
仕組み — IVFADC と OPQ で「全部は比べない」
ベクトル検索の素直な方法は、全ベクトルとの距離を計算して近い順に並べることです。vec1 の flat がこれにあたります。正確ですが、件数が増えると計算量もそのまま増えます。
vec1 の近似検索は、2つの工夫でこれを減らしています。
1つ目は IVF(転置ファイル) です。事前に k-means でベクトルをいくつかのグループ(バケット)に分けておき、検索時はクエリに近いバケットの中だけを調べます。バケット数は nbucket で決め、公式ドキュメントは「データ件数の平方根くらい」を目安にしています。100万件なら1,000前後です。検索時に何個のバケットを見るかは nprobe で指定し、既定値は全体の5%です。
2つ目は PQ / OPQ(直積量子化) です。ベクトルを短いコード(codesize バイト)に圧縮して保存し、距離も圧縮したまま近似で計算します。OPQ は圧縮前にベクトルを回転させ、圧縮で失われる情報を減らす改良版です。ADC(非対称距離計算)は、クエリ側は圧縮せず、データ側だけ圧縮した状態で距離を出す方式を指します。
近似検索を使う手順は次のとおりです。
-- 学習用データからモデルを作る
SELECT vec1_train(vector, '{codesize: 32, nbucket: 1024, quantizer: "opq", distance: "cos"}')
FROM training_set;
-- できたモデルでインデックスを作り直す
INSERT INTO vec1tbl(cmd, arg) VALUES('rebuild', :model);
ここで大事なのが、公式マニュアルの「vec1 で ANN を使うなら、リランクはほぼ必須」という注意です。圧縮した距離は近似なので、順位が入れ替わります。インデックスから多め(例: 100件)に候補を取り、元のベクトルで vec1_l2_distance() などを使って並べ直し、上位10件を返す。この2段構えが前提の設計です(圧縮しない codesize:0 の場合はリランク不要)。
この方式は、Facebook(Meta)の Faiss でおなじみの組み合わせです。HNSW のようなグラフ型インデックスと比べると、メモリが少なくて済み、ディスク上のデータベースとも相性がよいのが利点です。一方で、グラフ型ほど高い再現率は出しにくくなります。公式のロードマップにも、HNSW や DiskANN のようなグラフ型インデックスは「検討中」と書かれています。
sqlite-vec との違い
SQLite のベクトル検索といえば、Alex Garcia 氏の sqlite-vec が広く使われてきました。sqlite-vec は依存なしの C で書かれ、「SQLite が動くところならどこでも動く」ことを掲げた拡張です。Python・Node.js・Ruby・Go・Rust などのパッケージがそろっていて、ブラウザでも WebAssembly で動きます。
vec1 は「近似検索のインデックスを IVFADC + 量子化という形で持つ」点が特徴です。ただし公式マニュアルは、件数が少ない場合(目安5,000件未満)や正確な結果が必要な場合は全件比較(NN モード)を勧めています。件数が増えるほど、バケットで候補を絞れる ANN モードが効いてきます。
逆に、vec1 はまだ WebAssembly 向けの SIMD に対応しておらず、ロードマップに残っています。int8 や float16 のベクトル、検索(クエリ)のマルチスレッド化も今後の項目です(学習とインデックス構築はすでに複数スレッドで動かせます)。sqlite-vec はすでに int8 とバイナリのベクトルに対応しています。ブラウザで動かしたい場合や、言語ごとのパッケージで手軽に入れたい場合は、今のところ sqlite-vec のほうが扱いやすいでしょう。
エンジニアへの影響
一番効いてくるのは 端末内で完結する検索(ローカル RAG) です。モバイルアプリやデスクトップアプリは、すでに SQLite をデータの置き場にしていることが多いです。ベクトルも同じファイルに入れられれば、別の検索エンジンを抱えずにすみます。オフラインでも検索でき、データを外へ送らない設計にもしやすくなります。
mattn 氏は、IPAdic の約22万語を使った yomivec という実装例を公開しています。この件数なら学習も量子化もしない全件比較(flat)で十分で、22万語の取り込みは約2秒で終わったと報告しています。辞書やメモ程度の規模なら、近似インデックスを使わなくても始められるということです。
ただし、本番投入はまだ早いです。公式は「1.0 までに必要な機能はそろった」としながら、同時に「テストはまだ不十分」「ほとんどの処理に最適化の余地がある」とも書いています。バージョン表記も、公式ページは 0.7、mattn 氏の記事は 0.8 と、変化の速い段階です。
現時点でのおすすめは次のとおりです。
- 試す: 手元のデータで flat と IVFADC の速度・再現率を比べ、
nbucketとnprobeの感覚をつかむ - 設計だけ寄せる: ベクトルを float32 の BLOB で持つ、リランク前提の2段検索にする、といった形にしておくと、あとで乗り換えやすい
- 待つ: 本番は、1.0 のリリースに加えて、amalgamation への同梱や各言語のバインディングのような手軽な配布形態が出そろってから判断する(筆者の考え。公式にバインディングの予定は書かれていません)
まとめ
- SQLite 公式のベクトル検索拡張 vec1 がソースツリーに入った。L2・コサイン距離に対応する
- IVFADC で調べるバケットを絞り、OPQ などで圧縮して、近似検索を速くしている
- 近似検索はリランクがほぼ必須。多めに取って元のベクトルで並べ直す
- amalgamation には入らず、ローダブル拡張として配られる。現在は 1.0 前で、テストは不十分
- sqlite-vec とは「IVFADC の近似インデックスが要るか」と「対応環境・ベクトル型の広さ」で使い分ける
SQLite の開発元が作る拡張なので、1.0 になれば長く安心して使える選択肢になるはずです。端末内の検索を考えているなら、今のうちに手元で触っておく価値があります。