
Imagine owning an e-commerce platform that lists a wide variety of experts, from fitness coaches and yoga masters to financial advisors.
Suppose a customer needs SEO services but isn’t familiar with the industry jargon. Instead of searching for ‘SEO,’ they type: ‘I need help from someone who can increase my website traffic.’ A conventional database (like SQL) would likely fail to return any results because the specific keywords don’t match.
This is where a Vector Database comes to the rescue. Rather than looking for exact word matches, vector databases represent data as mathematical coordinates. This allows the system to search through vast amounts of information based on conceptual similarity , connecting the user’s intent with the right service provider.

To make this work, we need an AI model to handle the embedding process. Once the data is converted into vectors, we store them in the Vector Database , which then enables our search capabilities.
Rather than sticking to theory, let’s look at a real-life example. Imagine my e-commerce website stores all available services in a traditional SQL Server table named offerings . The data structure would look like this:

As you can notice in our table, Service ID 101 is exactly what the customer needs. But how does a Vector Database actually find this result when the user types: ‘I need help from someone who can increase my website traffic’ ?
To demonstrate this, we first need to set up a Vector Database. For this example, I’ve chosen Qdrant . Qdrant is a powerful, open-source vector database that is free to use when running locally on your machine. You can find the official installation guide at the link below to get started.
Installation - Qdrant
Once you have successfully installed and started Qdrant via Docker, you can verify it’s running by visiting the built-in Web UI. Open your browser and navigate to: http://localhost:6333/dashboard

Next, we will begin embedding the data from our offerings table into the vector database.
To do this, we need an AI model. For this demonstration, I am using the ‘BAAI/bge-m3’ model. It is an excellent choice for beginners because it is lightweight enough to run on a standard laptop. A key advantage of this specific model is its native support for hybrid search (combining dense and sparse vectors), which ensures high accuracy even if your descriptions contain multiple languages or technical jargon.
Below is a simplified Python script demonstrating how to load the AI model, retrieve the data from SQL Server, and use a generate_embeddings() function to transform that text into vectors.
EMBEDDING_MODEL = "BAAI/bge-m3"
model = SentenceTransformer(EMBEDDING_MODEL) #Load the model
offerings = fetch_offerings(conn #Get data from offerings table
items_with_embeddings = generate_embeddings(offerings, model)
Before calling the generate_embeddings() method, I use a helper function called create_text_for_embedding(). This function concatenates the most important columns from our offerings table into a single string.
Instead of embedding just the description, we combine the Service Name, Category, and Description together. For our SEO example, the final text sent to the AI model looks like this:
“Service: Brand Catalyst Marketing | Category: Marketing | Description: Social media management, SEO, and pay-per-click advertising campaigns.”
By including the category and service name, we provide the AI with a richer context, which significantly improves the accuracy of our search results.
def create_text_for_embedding(item: Dict) -> str:
text_parts = [
f"Service: {item['name']}",
f"Category: {item['category']}" if item['category'] else "",
f"Description: {item['description']}" if item['description'] else ""
]
# Filter out empty parts
text_parts = [part for part in text_parts if part]
return " | ".join(text_parts)
def generate_embeddings(items: List[Dict], model: SentenceTransformer) -> List[Dict]:
"""Generate embeddings for all items using BGE-M3 model"""
texts = [create_text_for_embedding(item) for item in items]And we continue with the generate_embeddings method.
def generate_embeddings(items: List[Dict], model: SentenceTransformer) -> List[Dict]:
#...
# Generate embeddings in batches for efficiency
batch_size = 32
all_embeddings = []
for i in range(0, len(texts), batch_size):
batch_texts = texts[i:i + batch_size]
embeddings = model.encode(batch_texts, batch_size=batch_size, show_progress_bar=True)
all_embeddings.extend(embeddings)
print(f" Processed {min(i + batch_size, len(texts))}/{len(texts)} items...")Instead of process the table one row per row, I create a batch with size 32. So each batch will embed 32 rows of concatenate info from table offerings. The line model.encode is the embedding function, we just need to pass the batch_text and batch size to it.
And the return results embeddings,is the embedding result for this batch.







Join the conversation! Your thoughts help the community grow.