Semantic search finds conceptually similar content, not just keyword matches — powered by vector embeddings that represent meaning numerically. This guide covers building one on a VPS.
Semantic Search vs Traditional Keyword Search
Traditional search (see How to Add a Search Feature to a Static Site (Client-Side Search)) matches literal terms; semantic search finds content that's conceptually related even without shared exact keywords — a search for "canine companion" could match content about "dogs" despite no literal word overlap.
The Core Concept: Embeddings
An embedding model converts text into a numerical vector representing its semantic meaning — similar meanings produce similar vectors (measurable via distance/similarity metrics), the foundation that makes semantic search possible.
Step 1 — Choose an Embedding Model
pip install sentence-transformers --break-system-packages
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
Sentence-transformers provides several pre-trained embedding models with different size/quality trade-offs — a smaller model like this one runs efficiently even on CPU, appropriate for moderate-scale VPS deployment.
Step 2 — Generate Embeddings for Your Content
documents = ["First document text", "Second document text", ...]
embeddings = model.encode(documents)
Step 3 — Store Embeddings in a Vector Database
See How to Set Up a Vector Database (Qdrant) for AI Applications — a vector database provides efficient similarity search at scale, essential once your document collection grows beyond what naive in-memory comparison can handle efficiently.
from qdrant_client import QdrantClient
client = QdrantClient(url="http://localhost:6333")
client.upsert(collection_name="documents", points=[
{"id": i, "vector": emb.tolist(), "payload": {"text": doc}}
for i, (emb, doc) in enumerate(zip(embeddings, documents))
])
Step 4 — Perform a Semantic Search Query
query_embedding = model.encode("canine companion")
results = client.search(collection_name="documents", query_vector=query_embedding.tolist(), limit=5)
Returns the most semantically similar documents, ranked by vector similarity — genuinely different from keyword matching, capable of finding conceptually relevant results without exact term overlap.
Combining Semantic and Keyword Search (Hybrid Search)
Pure semantic search can sometimes miss exact-match precision that keyword search excels at — many production systems combine both approaches (hybrid search), weighting and merging results from each method for genuinely better overall relevance.
Choosing Embedding Model Size Appropriately
Larger embedding models generally produce more nuanced/accurate embeddings but require more compute — for VPS-based deployment without dedicated GPU, smaller efficient models are often the practical choice, balancing quality against your available resources.
Handling Longer Documents
Embedding models typically have a maximum input length — for longer documents, consider chunking (see the chunking strategies discussed in How to Deploy a RAG (Retrieval-Augmented Generation) Pipeline on a VPS) rather than truncating or attempting to embed excessively long text directly.
Updating the Index as Content Changes
Establish a process for re-embedding and updating the vector database when your underlying content changes — a semantic search index reflecting stale content provides a degraded, misleading search experience.
Common Errors
Search results seem semantically odd or irrelevant — verify you're using the same embedding model consistently for both indexing and querying; mixing different models produces incompatible vector spaces, resulting in essentially meaningless similarity scores.
Continue Reading
- How to Set Up a Vector Database (Qdrant) for AI Applications
- How to Deploy a RAG (Retrieval-Augmented Generation) Pipeline on a VPS
- How to Build a Document Q&A System with LangChain
Browse more articles in AI & Machine Learning on a VPS.