Vector Database Semantic Search: From Embedding Selection to Hybrid Retrieval Optimization
Why Vector Databases Are Booming
In 2026, if you haven't encountered vector databases yet, you've missed one of the most important infrastructures of the AI era. The paradigm shift from keyword search to semantic search is reshaping the entire search technology stack.
Keyword Search: User searches "apple" → only matches documents containing "apple" Semantic Search: User searches "apple" → understands you might want "iPhone", "MacBook", or "fruit nutrition"
This leap in capability comes from Embedding — converting text into numerical vectors in high-dimensional space, where semantically similar texts are closer together.
Embedding Model Selection
| Model | Dimensions | Max Tokens | Multilingual | Open Source | MTEB Rank |
|---|---|---|---|---|---|
| OpenAI text-embedding-3-large | 3072 | 8191 | ✅ | ❌ | Top 5 |
| OpenAI text-embedding-3-small | 1536 | 8191 | ✅ | ❌ | Top 15 |
| BGE-M3 | 1024 | 8192 | ✅ | ✅ | Top 10 |
| Cohere embed-v4 | 1024 | 128000 | ✅ | ❌ | Top 8 |
| GTE-Qwen2 | 1536 | 32768 | ✅ | ✅ | Top 3 |
Selection Guide
Accuracy + GPU available → GTE-Qwen2 / E5-Mistral-7B
Cost-effective + fast launch → OpenAI text-embedding-3-small
Chinese-focused + open source → BGE-M3 / GTE-Qwen2
Very long documents → Cohere embed-v4
Multilingual + hybrid search → BGE-M3
Vector Database Comparison
| Feature | Milvus | pgvector | Qdrant | Weaviate | Chroma |
|---|---|---|---|---|---|
| Type | Dedicated | PG Extension | Dedicated | Dedicated | Embedded |
| Index Types | HNSW, IVF_PQ, Flat, SCANN | HNSW, IVFFlat | HNSW | HNSW | HNSW |
| Horizontal Scale | ✅ Native | ❌ | ✅ Sharding | ✅ Sharding | ❌ |
| Hybrid Search | ✅ | ✅ (SQL) | ✅ | ✅ | ✅ |
| ACID Transactions | ❌ | ✅ | ❌ | ❌ | ❌ |
| Ops Complexity | High | Low | Medium | Medium | Very Low |
How to Choose?
Already using PostgreSQL → pgvector, zero additional ops cost 100M+ vectors → Milvus, native distributed Medium scale + Rust performance → Qdrant Rapid prototyping → Chroma GraphQL + multimodal → Weaviate
Spring Boot + pgvector Implementation
1. Setup
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(500) NOT NULL,
content TEXT NOT NULL,
source VARCHAR(200),
embedding vector(1536),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_documents_embedding ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
2. Vector Search Repository
@Repository
public class DocumentVectorRepository {
private final JdbcTemplate jdbcTemplate;
public List<DocumentSearchResult> searchSimilar(float[] queryEmbedding, int limit) {
String vectorStr = Arrays.stream(queryEmbedding)
.mapToObj(f -> String.format("%.6f", f))
.collect(Collectors.joining(",", "[", "]"));
String sql = """
SELECT id, title, content, source,
1 - (embedding <=> ?::vector) AS similarity
FROM documents
WHERE embedding IS NOT NULL
ORDER BY embedding <=> ?::vector
LIMIT ?
""";
return jdbcTemplate.query(sql,
(rs, rowNum) -> new DocumentSearchResult(
rs.getLong("id"), rs.getString("title"),
rs.getString("content"), rs.getString("source"),
rs.getDouble("similarity")
),
vectorStr, vectorStr, limit
);
}
}
3. Search Service
@Service
public class SemanticSearchService {
private final EmbeddingService embeddingService;
private final DocumentVectorRepository vectorRepository;
public List<DocumentSearchResult> search(String query, int limit) {
float[] queryEmbedding = embeddingService.generateEmbedding(query);
return vectorRepository.searchSimilar(queryEmbedding, limit);
}
}
Index Types: HNSW, IVF_PQ, Flat
| Index Type | Query Speed | Recall | Memory | Build Speed | Use Case |
|---|---|---|---|---|---|
| Flat | Slow | 100% | Low | Very Fast | <100K, accuracy priority |
| HNSW | Fast | High (>95%) | High | Medium | 100K-10M, general purpose |
| IVF_PQ | Fast | Medium (85-95%) | Low | Slow | 100M+, memory constrained |
| SCANN | Fastest | High | Medium | Slow | Milvus-specific, large scale |
HNSW Parameter Tuning
-- m: neighbors per node, higher = better recall but more memory
-- ef_construction: build-time search width, higher = better index quality
CREATE INDEX idx_documents_embedding ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- Adjust ef_search at query time
SET hnsw.ef_search = 100;
Rule of thumb:
m=16, ef_construction=64is the sweet spot for most scenarios.
Hybrid Search: Vector + BM25 Keyword Search
Pure vector search may fail for exact matches (specific IDs, product codes). Hybrid search fuses semantic and keyword search:
User Query
├──→ Embedding → Vector Search → Semantic Results (weight α)
├──→ Tokenize → BM25 Search → Keyword Results (weight β)
└──→ RRF Fusion → Final Ranking
RRF (Reciprocal Rank Fusion)
public List<DocumentSearchResult> hybridSearch(String query, int limit) {
float[] embedding = embeddingService.generateEmbedding(query);
List<DocumentSearchResult> vectorResults = vectorRepository.searchSimilar(embedding, 50);
List<DocumentSearchResult> keywordResults = fulltextRepository.search(query, 50);
Map<Long, Double> rrfScores = new HashMap<>();
int k = 60;
for (int i = 0; i < vectorResults.size(); i++) {
rrfScores.merge(vectorResults.get(i).getId(), 1.0 / (k + i + 1), Double::sum);
}
for (int i = 0; i < keywordResults.size(); i++) {
rrfScores.merge(keywordResults.get(i).getId(), 1.0 / (k + i + 1), Double::sum);
}
return rrfScores.entrySet().stream()
.sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
.limit(limit)
.collect(Collectors.toList());
}
Rerank
| Rerank Model | Latency | Accuracy Boost | Open Source |
|---|---|---|---|
| Cohere Rerank | ~100ms | +15-25% | ❌ |
| bge-reranker-v2-m3 | ~50ms | +10-20% | ✅ |
| Jina Reranker | ~80ms | +10-15% | ✅ |
Typical flow: Vector search Top 50 → Rerank → Return Top 10. Accuracy improves 15-25% with 50-100ms added latency.
Production Optimization
Dimension Selection
| Dimensions | Storage Cost | Accuracy | Use Case |
|---|---|---|---|
| 384 | Low | Medium | Low accuracy requirements |
| 768 | Medium | High | General purpose |
| 1536 | High | Very High | General high quality |
| 3072 | Very High | Highest | Accuracy priority |
Quantization
// Matryoshka dimension truncation: 1536 → 768, storage halved, accuracy loss <3%
public float[] truncateEmbedding(float[] embedding, int targetDim) {
float[] truncated = new float[targetDim];
System.arraycopy(embedding, 0, truncated, 0, targetDim);
return truncated;
}
// Int8 quantization: float32 → int8, storage reduced 75%
public byte[] quantizeToInt8(float[] embedding) {
float maxAbs = 0;
for (float f : embedding) maxAbs = Math.max(maxAbs, Math.abs(f));
byte[] quantized = new byte[embedding.length];
for (int i = 0; i < embedding.length; i++) {
quantized[i] = (byte) (embedding[i] / maxAbs * 127);
}
return quantized;
}
Cost Analysis: Self-Hosted vs Cloud
| Dimension | Self-Hosted Milvus | Zilliz Cloud | Pinecone | pgvector |
|---|---|---|---|---|
| 1M × 1536d | ~$50/mo | ~$65/mo | ~$70/mo | ~$30/mo |
| 10M × 1536d | ~$200/mo | ~$300/mo | ~$350/mo | ~$150/mo |
| Ops Cost | High | None | None | Low |
| Scalability | Manual | Auto | Auto | Manual |
| Data Security | Full control | Cloud | Cloud | Full control |
Recommendation: Start with pgvector (if you already have PostgreSQL), consider Milvus or Zilliz Cloud when daily vector additions exceed 100K.
Summary
Vector databases and semantic search deliver tremendous value in these scenarios:
- Knowledge Base / RAG: AI answers based on enterprise private data
- Recommendation Systems: Content-based similarity recommendations
- Semantic Deduplication: Identify semantically identical but differently worded content
- Smart Customer Service: Understand user intent rather than keyword matching
The paradigm shift from keywords to semantics is fundamentally an upgrade from "matching literal text" to "understanding intent."
Try these browser-local tools — no sign-up required →