MMohan Vishe
All projects
Retrieval

Product Similarity API

Semantic product search with structured filters inside the query, not after it.

View code on GitHubJupyter NotebookMIT

Semantic search with real constraints

Pure vector search returns things that are similar. Shoppers want things that are similar and under a price, and above a rating. Filtering after retrieval quietly loses products: anything in range that sits outside the fixed window of nearest neighbours never comes back.

So price is stored as a number at ingest, and price and rating go into Chroma's where clause — the nearest neighbours are chosen from products that already satisfy the filters. Queries and descriptions pass through the same normalisation, and every result carries its cosine similarity, with an optional cut-off, so a caller can see how close a match really is. Served over FastAPI, with tests and a retrieval eval that run in CI.

Measured, not assumed

A 40-query labelled set over the 16-product catalogue — paraphrases, intent, negation, filtered and off-topic queries — runs through the API's own search function in CI, and fails the build if the numbers drift.

  • recall@3 0.958, MRR 0.922 at the API defaults. Paraphrase and intent queries put the right product first every time; filtered queries score 0.833.
  • No similarity floor cleanly separates off-topic queries. The best off-topic score (0.216) sits just 0.03 below the weakest correct first hit (0.247), so the cut-off stays optional, with 0.20 documented as a starting point rather than a tuned default.
  • The embedding model ignores negation, so exclusions are now parsed out of the query ("not a laptop", "without", "except") and applied as a filter. On a 34-query held-out set committed before the change, MRR rose from 0.809 to 0.905, and ruled-out products left the top three on 9 of 9 negation queries. Hedges like "not too expensive" are left alone.

Both sets are small and written by me, so these numbers describe this catalogue, not retrieval in general. Keyword (BM25) and hybrid retrieval are available as options; dense stays the default by a rule fixed before the held-out run.

Next

Synonyms for the exclusion parser (so "phone" matches "Smartphone"), and an independently written query set.