Vector Backends
Spectacles stores every embedding as JSON in spectacles_imagemetadata regardless of backend. The backend only decides how similarity search is computed.
Scan backend (default)
Loads every embedded record and computes cosine similarity in PHP. Works on any database Craft supports — MySQL, MariaDB, or Postgres. Fine for libraries up to a few thousand images.
Pros:
- Zero setup, works everywhere.
- No DB extension required.
- JSON embedding doubles as a portable backup.
Cons:
- Loads every record into memory per query — gets slow past a few thousand images.
- No native sorting; cosine math runs once per row in PHP.
pgvector backend
If you’re on Postgres with the pgvector extension installed, Spectacles auto-detects it and uses a dedicated spectacles_imagevectors table with a real vector column. Cosine distance is computed in C via the <=> operator.
Setup:
-- inside your Postgres database
CREATE EXTENSION IF NOT EXISTS vector;
Then run php craft up — the migration will detect the extension and create spectacles_imagevectors. From there, Spectacles will use it automatically.
Adding an index at scale
Spectacles doesn’t install a vector index by default because optimal index parameters depend on your vector dimension (different providers produce different sizes). Once your dimension is stable, add one yourself:
CREATE INDEX ON spectacles_imagevectors
USING hnsw (embedding vector_cosine_ops);
HNSW gives sub-linear ANN lookups at the cost of a small index-build time. For smaller libraries, ivfflat is also fine.
Forcing a backend
Open Spectacles settings and choose:
- Auto — pgvector if available, otherwise scan. Default.
- PHP scan — always use scan, even if pgvector is installed.
- pgvector — fail rather than fall back. Useful for catching misconfiguration in production.
Future backends
The SimilarityBackend interface in src/services/similarity/ is straightforward — search(), index(), deleteForAsset(), isAvailable(). Pinecone, Qdrant, and Weaviate backends are good candidates and PRs are welcome.