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=64 is the sweet spot for most scenarios.


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:

  1. Knowledge Base / RAG: AI answers based on enterprise private data
  2. Recommendation Systems: Content-based similarity recommendations
  3. Semantic Deduplication: Identify semantically identical but differently worded content
  4. 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 →

#向量数据库#语义搜索#Embedding#Milvus#pgvector