sqlite-vec について
sqlite-vec は、SQLite データベース内でベクトル埋め込みを保存し、類似検索を行う拡張機能です。別のベクトルデータベースを使わずに検索機能を構築する開発者向けで、複数のベクトル型、メタデータフィルター、パーティションに対応します。
主な機能
- 01SQLite 内でのベクトル保存
- 02KNN 類似検索クエリ
- 03float、int8、bit ベクトル対応
- 04メタデータフィルターとパーティションキー
- 05ベクトル演算と量子化
活用シーン
- 01SQLite アプリへの類似検索の追加
- 02メタデータによる近傍結果の絞り込み
- 03テナント別のベクトル検索の分割
- 04ベクトル変換と量子化の実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ existential-birds/ beagle --skill sqlite-vecインストール後、Claude Code で/sqlite-vecを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/tables.mdoperations.mdqueries.mdsetup.md詳細
sqlite-vec
sqlite-vec は、ベクトル類似検索向けの軽量な SQLite 拡張機能です。外部のベクトルデータベースを使わずに、SQLite データベース内でベクトル埋め込みを直接保存して検索できます。
ゲート
ストレージと KNN クエリを組み込む際は、以下の手順を順番に実行してください。各手順には、結果を本番環境で利用したり、レビューコメントに記載したりする前に確認できる客観的な合格基準があります。
- 次元の固定 —
float[N]、int8[N]、またはbit[N]のNが、埋め込みモデルの出力長(および適用する Matryoshka スライス)と一致していること。合格基準: 同じNがCREATE VIRTUAL TABLEDDL とシリアライズされたベクトルの長さ(len(vector)またはモデルの仕様に記載された次元数)の両方に指定されています。 - シリアライズの一致 — カラム型と Python(または他の言語)のヘルパーが対応していること:
float[N]にはserialize_float32、int8[N]にはserialize_int8、bit[N]にはバイナリ規則を使用します。合格基準: 既知のテストベクトルを使った往復挿入を少なくとも 1 回実行し、同じシリアライザーを使ったMATCHクエリで期待する行が返されます(例:k = 1でその行が返されます)。 - ドキュメントに裏付けられた境界条件の主張 — 距離指標の選択、メタデータフィルター演算子、パーティションキーの規則、バージョン固有の動作について主張できるのは、このスキルまたは リソース に記載された公式ドキュメントで確認できる場合のみです。合格基準: その主張を確定事項として扱う前に、該当する URL またはドキュメントのセクションを成果物(issue、PR、またはメモ)に引用します。
クイックリファレンス
拡張機能の読み込み
import sqlite3
import sqlite_vec
from sqlite_vec import serialize_float32
db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
sqlite_vec.load(db)
db.enable_load_extension(False)
基本的な KNN クエリ
-- Create table
CREATE VIRTUAL TABLE vec_items USING vec0(
embedding float[4]
);
-- Insert vectors (use serialize_float32() in Python)
INSERT INTO vec_items(rowid, embedding)
VALUES (1, X'CDCCCC3DCDCC4C3E9A99993E00008040');
-- KNN query
SELECT rowid, distance
FROM vec_items
WHERE embedding MATCH '[0.3, 0.3, 0.3, 0.3]'
AND k = 10
ORDER BY distance;
主な概念
ベクトル型
sqlite-vec は、次の 3 種類のベクトル要素型をサポートしています。
-
float[N] - 32 ビット浮動小数点数(要素あたり 4 バイト)
- 埋め込みで最も一般的です(OpenAI、Cohere など)
- 例:text-embedding-3-small の場合は
float[1536]
-
int8[N] - 8 ビット符号付き整数(要素あたり 1 バイト)
- 範囲:-128 ~ 127
- 量子化された埋め込みに使用します
-
bit[N] - バイナリベクトル(要素あたり 1 ビット、バイト単位でパック)
- 最もコンパクトなストレージ形式です
- バイナリ量子化に使用します
バイナリシリアライズ形式
ベクトルは、バイナリ BLOB または JSON 文字列として渡す必要があります。Python のヘルパー関数:
from sqlite_vec import serialize_float32, serialize_int8
import struct
# Float32 vectors
vector = [0.1, 0.2, 0.3, 0.4]
blob = serialize_float32(vector)
# Equivalent to: struct.pack("%sf" % len(vector), *vector)
# Int8 vectors
int_vector = [1, 2, 3, 4]
blob = serialize_int8(int_vector)
# Equivalent to: struct.pack("%sb" % len(int_vector), *int_vector)
NumPy 配列は直接渡せます(float32 にキャストする必要があります):
import numpy as np
embedding = np.array([0.1, 0.2, 0.3, 0.4]).astype(np.float32)
db.execute("SELECT vec_length(?)", [embedding])
vec0 仮想テーブル
vec0 仮想テーブルは、ベクトル検索の主要なデータ構造です。
基本的なテーブルの作成
CREATE VIRTUAL TABLE vec_documents USING vec0(
document_id integer primary key,
contents_embedding float[768]
);
距離指標
CREATE VIRTUAL TABLE vec_items USING vec0(
embedding float[768] distance_metric=cosine
);
サポートされる指標:l2(デフォルト)、cosine、hamming(ビットベクトルのみ)
カラム型
vec0 テーブルは、次の 4 種類のカラム型をサポートしています。
- ベクトルカラム - 埋め込みを保存します(float[N]、int8[N]、bit[N])
- メタデータカラム - インデックスが作成され、KNN クエリでフィルター処理できます
- パーティションキーカラム - 絞り込み済みクエリを高速化する内部シャーディングに使用します
- 補助カラム - インデックスなしでデータを保存します(先頭に + を付けます)
すべてのカラム型を含む例:
CREATE VIRTUAL TABLE vec_knowledge_base USING vec0(
document_id integer primary key,
-- Partition keys (sharding)
organization_id integer partition key,
created_month text partition key,
-- Vector column
content_embedding float[768] distance_metric=cosine,
-- Metadata columns (filterable in KNN)
document_type text,
language text,
word_count integer,
is_public boolean,
-- Auxiliary columns (not filterable)
+title text,
+full_content text,
+url text
);
KNN クエリ
標準的なクエリ構文
SELECT rowid, distance
FROM vec_items
WHERE embedding MATCH ?
AND k = 10
ORDER BY distance;
主な要素:
WHERE embedding MATCH ?- KNN クエリを実行しますAND k = 10- 近傍を 10 件に制限しますORDER BY distance- 近さの順に結果を並べ替えます
メタデータによるフィルタリング
SELECT document_id, distance
FROM vec_movies
WHERE synopsis_embedding MATCH ?
AND k = 5
AND genre = 'scifi'
AND num_reviews BETWEEN 100 AND 500
AND mean_rating > 3.5
AND contains_violence = false
ORDER BY distance;
メタデータでサポートされる演算子:=、!=、>、>=、<、<=、BETWEEN
サポートされない演算子:IS NULL、LIKE、GLOB、REGEXP、スカラー関数
パーティションキーによるフィルタリング
SELECT document_id, distance
FROM vec_documents
WHERE contents_embedding MATCH ?
AND k = 20
AND user_id = 123 -- Partition key pre-filters
ORDER BY distance;
パーティションキーを使うと、マルチテナントまたは時間ベースのシャーディングが可能になります。ベストプラクティス:
- 一意のパーティション値ごとに 100 件以上のベクトルを保持します
- パーティションキーは最大 1~2 個にします
- 過度なシャーディング(一意の値が多すぎる状態)は避けます
ソーステーブルとの結合
WITH knn_matches AS (
SELECT document_id, distance
FROM vec_documents
WHERE contents_embedding MATCH ?
AND k = 10
)
SELECT
documents.id,
documents.title,
knn_matches.distance
FROM knn_matches
LEFT JOIN documents ON documents.id = knn_matches.document_id
ORDER BY knn_matches.distance;
距離関数
手動で距離を計算する場合(vec0 以外のテーブル):
-- L2 distance
SELECT vec_distance_l2('[1, 2]', '[3, 4]');
-- 2.8284...
-- Cosine distance
SELECT vec_distance_cosine('[1, 1]', '[2, 2]');
-- ~0.0
-- Hamming distance (bit vectors)
SELECT vec_distance_hamming(vec_bit(X'F0'), vec_bit(X'0F'));
-- 8
ベクトル演算
コンストラクター
-- Float32
SELECT vec_f32('[.1, .2, .3, 4]'); -- Subtype 223
-- Int8
SELECT vec_int8('[1, 2, 3, 4]'); -- Subtype 225
-- Bit
SELECT vec_bit(X'F0'); -- Subtype 224
メタデータ関数
-- Get length
SELECT vec_length('[1, 2, 3]'); -- 3
-- Get type
SELECT vec_type(vec_int8('[1, 2]')); -- 'int8'
-- Convert to JSON
SELECT vec_to_json(vec_f32('[1, 2]')); -- '[1.000000,2.000000]'
算術演算
-- Add vectors
SELECT vec_to_json(
vec_add('[.1, .2, .3]', '[.4, .5, .6]')
);
-- '[0.500000,0.700000,0.900000]'
-- Subtract vectors
SELECT vec_to_json(
vec_sub('[.1, .2, .3]', '[.4, .5, .6]')
);
-- '[-0.300000,-0.300000,-0.300000]'
変換
-- Normalize (L2 norm)
SELECT vec_to_json(
vec_normalize('[2, 3, 1, -4]')
);
-- '[0.365148,0.547723,0.182574,-0.730297]'
-- Slice (for Matryoshka embeddings)
SELECT vec_to_json(
vec_slice('[1, 2, 3, 4]', 0, 2)
);
-- '[1.000000,2.000000]'
-- Matryoshka pattern: slice then normalize
SELECT vec_normalize(vec_slice(embedding, 0, 256))
FROM vec_items;
量子化
-- Binary quantization (positive→1, negative→0)
SELECT vec_quantize_binary('[1, 2, 3, 4, -5, -6, -7, -8]');
-- X'0F'
-- Visualize
SELECT vec_to_json(
vec_quantize_binary('[1, 2, -3, 4, -5, 6, -7, 8]')
);
-- '[0,1,0,0,1,0,1,0]'
反復処理
-- Iterate through elements
SELECT rowid, value
FROM vec_each('[1, 2, 3, 4]');
/*
┌───────┬───────┐
│ rowid │ value │
├───────┼───────┤
│ 0 │ 1 │
│ 1 │ 2 │
│ 2 │ 3 │
│ 3 │ 4 │
└───────┴───────┘
*/
Python との統合
完全な例
import sqlite3
import sqlite_vec
from sqlite_vec import serialize_float32
# Setup
db = sqlite3.connect(":memory:")
db.enable_load_extension(True)
sqlite_vec.load(db)
db.enable_load_extension(False)
# Create table
db.execute("""
CREATE VIRTUAL TABLE vec_items USING vec0(
embedding float[4]
)
""")
# Insert vectors
items = [
(1, [0.1, 0.1, 0.1, 0.1]),
(2, [0.2, 0.2, 0.2, 0.2]),
(3, [0.3, 0.3, 0.3, 0.3])
]
with db:
for rowid, vector in items:
db.execute(
"INSERT INTO vec_items(rowid, embedding) VALUES (?, ?)",
[rowid, serialize_float32(vector)]
)
# Query
query = [0.25, 0.25, 0.25, 0.25]
results = db.execute(
"""
SELECT rowid, distance
FROM vec_items
WHERE embedding MATCH ?
AND k = 2
ORDER BY distance
""",
[serialize_float32(query)]
).fetchall()
for rowid, distance in results:
print(f"rowid={rowid}, distance={distance}")
埋め込み API との統合
from openai import OpenAI
from sqlite_vec import serialize_float32
client = OpenAI()
# Generate embedding
response = client.embeddings.create(
input="your text here",
model="text-embedding-3-small"
)
embedding = response.data[0].embedding
# Store in sqlite-vec
db.execute(
"INSERT INTO vec_documents(id, embedding) VALUES(?, ?)",
[doc_id, serialize_float32(embedding)]
)
# Query
query_embedding = client.embeddings.create(
input="search query",
model="text-embedding-3-small"
).data[0].embedding
results = db.execute(
"""
SELECT id, distance
FROM vec_documents
WHERE embedding MATCH ?
AND k = 10
""",
[serialize_float32(query_embedding)]
).fetchall()
パフォーマンスに関するヒント
- マルチテナントまたは時間で絞り込むクエリには、パーティションキーを使用します
- k は適切な値に保ちます(ほとんどのユースケースでは 10~100)
- 可能な場合は、メタデータ列でフィルタリングします
- 埋め込みに適した距離メトリックを選択します
- トランザクション内で操作をバッチ処理します
- フィルタリングに不要な大きなデータには、補助列を使用します
- パーティションキーの一意の値ごとに 100 個以上のベクトルがあることを確認します
一般的なパターン
マルチテナント検索
CREATE VIRTUAL TABLE vec_docs USING vec0(
doc_id integer primary key,
user_id integer partition key,
embedding float[768]
);
SELECT doc_id, distance
FROM vec_docs
WHERE embedding MATCH ? AND k = 10 AND user_id = 123;
ハイブリッド検索
SELECT product_id, distance
FROM vec_products
WHERE embedding MATCH ?
AND k = 20
AND category = 'electronics'
AND price < 1000.0
ORDER BY distance;
Matryoshka 埋め込み
-- Adaptive dimensions: slice then normalize
SELECT vec_normalize(vec_slice(embedding, 0, 256))
FROM vec_items;
参考ファイル
- setup.md - インストール、拡張機能の読み込み、Python バインディング、NumPy との統合
- tables.md - vec0 テーブルの作成、列の型、メタデータ列/パーティション列/補助列
- queries.md - KNN クエリのパターン、メタデータによるフィルタリング、パーティションによるフィルタリング、最適化
- operations.md - ベクトル操作、コンストラクター、変換、量子化、バッチ操作
リソース
- 公式ドキュメント:https://alexgarcia.xyz/sqlite-vec
- GitHub リポジトリ:https://github.com/asg017/sqlite-vec
- Python パッケージ:https://pypi.org/project/sqlite-vec/
- API リファレンス:https://alexgarcia.xyz/sqlite-vec/api-reference.html