2023 年末の Advent Calendar の時期に、
の 2 本の記事を書きましたが、そこから半年が経過する間に追加された機能があるので、まとめてみました。
といいつつ中身はほぼ README からの抜粋です。
0.6.0 の追加機能
パラレル処理による HNSW インデックス作成の高速化
README の Index Build Time にあるように、CPU コアの数が多い環境で、処理の並列化により HNSW インデックス作成を高速化できるようになりました。
SET max_parallel_maintenance_workers = 【並列処理に使うワーカー数(デフォルト:2)】;
で並列数を指定することができます。
max_parallel_maintenance_workers
の数を増やすときは、パラレルワーカー自体の数(max_parallel_workers
:デフォルトは8
)の数も調整する必要があるかも知れません。
Supabase のブログ記事 に 0.5.x との比較がまとめられています。
0.7.0 の追加機能
主に、ベクトル計算やインデックス作成の負荷低減に有効な機能が追加されています。
こちらも、Supabase のブログ記事にまとめられています。
半精度ベクトル・半精度インデックス
これまでは 32 ビット(4 バイト)浮動小数点数によるベクトルデータをサポートしていましたが、16 ビット(2 バイト)浮動小数点数によるベクトルデータおよびインデックスもサポートしました。
CREATE TABLE items (id bigserial PRIMARY KEY, embedding halfvec(3));
CREATE INDEX ON items USING hnsw ((embedding::halfvec(3)) halfvec_l2_ops);
次元あたりの容量が半減した分、インデックス作成可能な次元数が倍増しました(最大 4,000 次元)。
バイナリ(ビット)ベクトルおよびバイナリ量子化・バイナリインデックス
半精度だけではなくバイナリ(ビット)ベクトルおよびバイナリ量子化・バイナリインデックスもサポートしました。
CREATE TABLE items (id bigserial PRIMARY KEY, embedding bit(3));
INSERT INTO items (embedding) VALUES ('000'), ('111');
2 進表現の文字列でデータを投入するようです。
SELECT * FROM items ORDER BY embedding <~> '101' LIMIT 5;
近傍探索するときは、ハミング距離(<~>
)またはジャッカード距離(ジャッカード類似度・<%>
)を使います。
CREATE INDEX ON items USING hnsw ((binary_quantize(embedding)::bit(3)) bit_hamming_ops);
こちらはハミング距離用のインデックス作成例です。
次元あたりの容量が減少した分、インデックス作成可能な次元数が増加しました(最大 64,000 次元)。
また、Cohere Embed のような、API でバイナリベクトルの出力をサポートしている埋め込みモデルを使わなくても、このバイナリ量子化関数を使って 32 ビットのベクトルからバイナリベクトルを生成することができます。
SELECT * FROM (
SELECT * FROM items ORDER BY binary_quantize(embedding)::bit(3) <~> binary_quantize('[1,-2,3]') LIMIT 20
) ORDER BY embedding <=> '[1,-2,3]' LIMIT 5;
最初にバイナリ量子化ベクトル(インデックス)による近傍探索によって 20 件の候補に絞り込んでおき、その中から 32 ビットのベクトルによって上位 5 件に絞り込むやり方です。
一定の精度は確保しつつ、ベクトルの距離比較の計算負荷を下げる手法ですね。
2024/5/24 追記:
Zenn に追加の記事を書きました。
疎ベクトル
0 が多く含まれるベクトルを扱う際に、疎ベクトルの機能(表現)を使うことで記憶容量の削減が可能になりました。
前述の Supabase のブログ記事を参照してください。
CREATE TABLE items (id bigserial PRIMARY KEY, embedding sparsevec(5));
INSERT INTO items (embedding) VALUES ('{1:1,3:2,5:3}/5'), ('{1:4,3:5,5:6}/5');
サブベクトルのインデックス化
元のベクトルからサブベクトルを抽出してインデックスを作成することで、インデックス作成および検索時の計算負荷を低減できるようになりました。
CREATE INDEX ON items USING hnsw ((subvector(embedding, 1, 3)::vector(3)) vector_cosine_ops);
SELECT * FROM items ORDER BY subvector(embedding, 1, 3)::vector(3) <=> subvector('[1,2,3,4,5]'::vector, 1, 3) LIMIT 5;
SELECT * FROM (
SELECT * FROM items ORDER BY subvector(embedding, 1, 3)::vector(3) <=> subvector('[1,2,3,4,5]'::vector, 1, 3) LIMIT 20
) ORDER BY embedding <=> '[1,2,3,4,5]' LIMIT 5;
バイナリインデックスを使った Re-rank と同様のことができます。
その他
L1 距離(マンハッタン距離・<+>
)による比較もサポートされました。
ベクトルデータの精度(タイプ)別に使用可能な関数などが README の Reference にまとめられています。
2024/8/18 追記:
pgvector による HNSW インデックス、およびバイナリ量子化の弱点を補う目的で登場した pgvectorscale を(少し)試してみた記事はこちら ↓ です。
試してみた内容にはあまり意味はありませんが、
- 記事末尾の(2024/8/16 以降の)追記
- 当該追記からリンクしている Timescale 社のブログ記事
に、pgvector(0.7.0 時点)の問題点と pgvectorscale における改善アプローチが記されていますので、よかったらご覧ください。