itsjorigoBLOG
←︎ Back to BlogAI

6 min read

Adding Semantic Search to a Wedding Planning App with Qdrant

SCROLL

How I integrated a vector database into a MERN stack application to power similarity-based vendor recommendations — and what surprised me along the way.

The SerendipWeds wedding planning app started as a standard MERN stack project — MongoDB, Express, React, Node. The recommendation feature was initially a simple keyword match: search for "photographer" in Colombo and get back all photographers in Colombo. It worked, but it felt hollow. A bride who searches for "romantic, intimate outdoor ceremony" should not get a list of every wedding venue in the country.

Why Qdrant

I chose Qdrant over Pinecone and Weaviate primarily because of the self-hosted option. For a personal project, I did not want to pay for a managed vector database. Qdrant runs cleanly in Docker, has a good Python client, and the filtering syntax — combining vector similarity with structured metadata filters — was exactly what I needed to scope results by location and budget before ranking by semantic similarity.

The Architecture

I added a Flask microservice alongside the Node.js backend to handle embedding generation and vector search. The reason for a separate service rather than a Node.js package was simple: the Python ML ecosystem is far better for embedding models. I used a sentence-transformers model to embed vendor profiles at write time, storing the vectors in Qdrant alongside the vendor ID. At query time, the user's search text was embedded with the same model and queried against Qdrant with location and budget filters applied.

What Surprised Me

The quality of results was better than I expected immediately. Searching for "rustic garden setting with natural light" returned outdoor venues with garden features ahead of indoor ballrooms — without any explicit keyword match. The model had learned enough about these concepts from its training data that the semantic proximity was meaningful.

What I did not expect was the cold start problem. Vendor profiles written in mixed English and Sinhala produced inconsistent embeddings because the model had much better coverage of English. I ended up normalising all vendor descriptions to English before embedding, which was an extra preprocessing step I had not planned for.

Would I Use It Again

Yes, without hesitation, for any application where users express intent in natural language rather than structured queries. The integration cost is low — a few hundred lines of Python, a Docker container, and some thought about your embedding strategy. The UX improvement over keyword search is immediately visible.