How to Intermediate · 4 min read

How to implement semantic product search

Quick answer
Implement semantic product search by encoding product descriptions and user queries into vector embeddings using models like text-embedding-3-small. Then perform similarity search with vector databases such as FAISS to retrieve relevant products based on semantic meaning rather than keywords.

PREREQUISITES

  • Python 3.8+
  • OpenAI API key (free tier works)
  • pip install openai>=1.0 faiss-cpu numpy

Setup

Install required Python packages and set your OpenAI API key as an environment variable.

bash
pip install openai faiss-cpu numpy

# Set environment variable in your shell
export OPENAI_API_KEY=os.environ["OPENAI_API_KEY"]
output
Requirement already satisfied: openai in ...
Requirement already satisfied: faiss-cpu in ...
Requirement already satisfied: numpy in ...

Step by step

This example encodes product descriptions and a user query into embeddings, then uses FAISS to find the top 3 semantically similar products.

python
import os
import numpy as np
import faiss
from openai import OpenAI

# Initialize OpenAI client
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

# Sample product catalog
products = [
    {"id": 1, "name": "Wireless Bluetooth Headphones", "description": "High quality wireless headphones with noise cancellation."},
    {"id": 2, "name": "Running Shoes", "description": "Lightweight running shoes with breathable mesh."},
    {"id": 3, "name": "Smartphone Case", "description": "Durable case compatible with latest smartphone models."},
    {"id": 4, "name": "Electric Toothbrush", "description": "Rechargeable toothbrush with multiple cleaning modes."}
]

# Function to get embeddings from OpenAI
def get_embedding(text):
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return np.array(response.data[0].embedding, dtype=np.float32)

# Create embeddings for all products
product_embeddings = np.array([get_embedding(p["description"]) for p in products])

# Build FAISS index
dimension = product_embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(product_embeddings)

# User query
query = "Looking for noise cancelling headphones"
query_embedding = get_embedding(query)

# Search top 3 similar products
k = 3
D, I = index.search(np.array([query_embedding]), k)

print("Top products for query:", query)
for rank, idx in enumerate(I[0]):
    product = products[idx]
    print(f"{rank + 1}. {product['name']} - {product['description']}")
output
Top products for query: Looking for noise cancelling headphones
1. Wireless Bluetooth Headphones - High quality wireless headphones with noise cancellation.
2. Electric Toothbrush - Rechargeable toothbrush with multiple cleaning modes.
3. Smartphone Case - Durable case compatible with latest smartphone models.

Common variations

  • Use async calls with asyncio and OpenAI's async client for higher throughput.
  • Switch to other embedding models like claude-3-5-sonnet embeddings or sentence-transformers for local inference.
  • Use vector databases like Pinecone or Chroma for scalable, persistent search.

Troubleshooting

  • If embeddings are slow, batch multiple texts per request to OpenAI.
  • If search results are irrelevant, verify embedding model choice and consider fine-tuning or prompt engineering.
  • Ensure faiss index dimension matches embedding size exactly to avoid errors.

Key Takeaways

  • Use vector embeddings to represent product descriptions and queries for semantic similarity.
  • FAISS provides fast in-memory similarity search for small to medium catalogs.
  • OpenAI's text-embedding-3-small is a reliable embedding model for semantic search.
  • For production, consider scalable vector DBs like Pinecone or Chroma.
  • Batch embedding requests and verify index dimensions to optimize performance.
Verified 2026-04 · text-embedding-3-small, gpt-4o, claude-3-5-sonnet-20241022
Verify ↗