How do you choose between VectorStore implementations like PgVector, Redis, and Chroma, and what configuration matters?
answer
- same interface -> swap via config
- Pg = reuse Postgres, SQL/JSONB filter, HNSW/IVFFlat
- Redis = in-memory low latency
- Chroma = lightweight AI-first
- dimensions + distance + index must match model
basics
~20 sAll implement the same VectorStore interface, so code stays the same — you pick based on your existing infrastructure. Use PgVector if you already run Postgres, Redis if you need speed and already run Redis, Chroma for a lightweight AI-focused store. Key config: dimensions, distance metric, and index type.
solid answer
~40 sThe whole point of the VectorStore abstraction is that PgVectorStore, RedisVectorStore, and ChromaVectorStore are interchangeable behind one interface — swapping is config, not code. Choose by operational fit: PgVector reuses an existing Postgres, gives ACID and SQL metadata filtering, and supports HNSW/IVFFlat indexes plus cosine/euclidean/inner-product distance — great when you already run Postgres. Redis (RediSearch) is in-memory, very low latency, good for high-QPS retrieval and when Redis is already in your stack. Chroma is a purpose-built, lightweight vector DB nice for local dev and small services. Critical config regardless of store: the vector dimension must equal your EmbeddingModel.dimensions(); the distance metric (usually cosine); the index type and its build parameters; and whether Spring initializes the schema (initialize-schema). Because the app code is identical, prototype with SimpleVectorStore and promote to the real store via properties.
code
java · 28 lines// application.yml — swapping stores is configuration, not code.
//
// PgVector:
// spring.ai.vectorstore.pgvector:
// index-type: HNSW
// distance-type: COSINE_DISTANCE
// dimensions: 1536
// initialize-schema: true
//
// Redis:
// spring.ai.vectorstore.redis:
// initialize-schema: true
// index-name: my-index
// The application code is identical regardless of backend:
@Service
class RetrievalService {
private final VectorStore vectorStore; // Pg, Redis, or Chroma injected
RetrievalService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
List<Document> retrieve(String query) {
return vectorStore.similaritySearch(
SearchRequest.builder().query(query).topK(4).build());
}
}go deeper
Know several stores exist (Postgres/Redis/Chroma) behind one VectorStore interface.
Explain that swapping is config-only and name a selection heuristic based on existing infra.
Discuss distance metrics, HNSW vs IVFFlat, dimension matching, and initialize-schema vs migrations.
Weigh operational cost, durability/consistency guarantees, recall/latency tradeoffs, and schema-governance strategy when standardizing a store across services.
## One interface, many backends Every store implements `org.springframework.ai.vectorstore.VectorStore`, so `add`/`delete`/`similaritySearch` calls are identical across backends. Switching stores means changing the starter dependency and `spring.ai.vectorstore.*` properties — **not** your service code. This is a deliberate portability guarantee. ## `PgVectorStore` (Postgres + pgvector extension) - **Why**: you already run Postgres; you get transactions, backups, SQL tooling, and metadata stored as JSONB filtered via SQL. - **Distance**: `COSINE_DISTANCE` (default), `EUCLIDEAN_DISTANCE`, `NEGATIVE_INNER_PRODUCT`. - **Index**: `HNSW` (default, high recall/latency tradeoff), `IVFFLAT`, or `NONE` (exact scan, fine for small data). - **Config**: `spring.ai.vectorstore.pgvector.index-type`, `.distance-type`, `.dimensions`, `.initialize-schema=true` to auto-create table/index. - **Note**: requires the `vector` extension installed in Postgres. ## `RedisVectorStore` (Redis Stack / RediSearch) - **Why**: in-memory, very low latency, high throughput; natural if Redis is already your cache/session store. - Uses RediSearch vector fields; supports HNSW/FLAT and cosine/IP/L2. - **Tradeoff**: durability depends on Redis persistence config; memory-bound capacity. ## `ChromaVectorStore` (Chroma DB) - **Why**: lightweight, AI-first, easy to run locally in a container; pleasant for prototypes and small services. - Runs as a separate service the app talks to over HTTP. ## `SimpleVectorStore` - In-memory, no external dependency; brute-force cosine over an in-heap map. **For tests/prototypes only** — not durable, not scalable. Can persist/load to a JSON file for convenience. ## Other supported stores Milvus, Qdrant, Weaviate, Elasticsearch, Azure AI Search, Neo4j, MongoDB Atlas, Oracle, Typesense, etc. — same interface. ## Configuration that always matters 1. **Dimensions**: must equal `EmbeddingModel.dimensions()`. A mismatch fails on insert or corrupts search. 2. **Distance metric**: cosine is the common default for text embeddings; match how the model was trained. 3. **Index type & params**: HNSW (better recall, more memory/build cost) vs IVFFlat/FLAT; approximate indexes trade a little recall for big speed gains. 4. **Schema initialization**: `initialize-schema` lets Spring create the table/collection/index; in prod many teams manage schema via migrations (e.g. Liquibase for pgvector) instead. 5. **Batching strategy**: `add` of large lists may be internally batched; huge ingests should be chunked. ## Selection heuristic - Already on Postgres, want transactional consistency + SQL filtering → **PgVector**. - Need lowest latency / high QPS, Redis already present → **Redis**. - Small/local/AI-focused prototype → **Chroma**. - Unit tests / quick demo → **SimpleVectorStore**. - Massive scale / specialized ANN → Milvus/Qdrant/Weaviate. ## Gotchas - Choosing a store you don't already operate adds ops burden; portability means you can defer the decision. - Approximate indexes (HNSW/IVFFlat) return *approximate* neighbors — recall is tunable, not perfect. - `initialize-schema=true` in prod can clash with migration-managed schemas. - Distance metric and dimension must be consistent for the life of the data; changing either requires re-indexing.
- Does switching from PgVector to Redis require changing your service code?No — both implement VectorStore, so add/delete/similaritySearch calls are unchanged. You swap the starter dependency and spring.ai.vectorstore.* properties. That portability is the abstraction's main value.
- What's the risk of approximate index types like HNSW or IVFFlat?They return approximate nearest neighbors, so recall is less than 100% — a truly relevant document can occasionally be missed. You tune index build/search parameters to trade recall against latency and memory; exact scan (NONE/FLAT) guarantees recall but is slow at scale.
saying these in an interview costs you the question
- Thinking each store needs different application code
- Setting a vector dimension that doesn't match the EmbeddingModel
- Assuming HNSW/IVFFlat give exact results
- Leaving initialize-schema=true in a migration-managed production DB