Case study
Marketplace Discovery Platform
Session feed ranking and hybrid search with offline eval, serving, and a product-style demo.
At a glance
Plain summary for recruiters and visitors. Technical detail follows below.
- What it is
- I built a marketplace discovery lab with session feed ranking and hybrid search on public event logs. Offline eval beats popularity on the sample holdout.
- What I owned
- Solo end to end. Ingest, DuckDB features, feed and search rankers, FastAPI serving, pytest contracts, and the frozen portfolio demo.
- Why it matters
- Shows how buyer-side teams can ship ranked feeds and search with honest baselines before scaling to full catalog traffic.
- Try it on this page vs full project
- This page runs frozen feed and search chips on a toy catalog. The full FastAPI console and training stack stay on request.

Problem
Marketplace buyers need relevant session feeds and search results. Teams need honest offline eval before scaling rankers to full traffic.
Method
Built ingest, DuckDB features, feed candidates with two-tower retrieval and LightGBM rerank, plus BM25 hybrid search with intent rules and policy filter. Evaluated with session leave-one-out and curated query sets.
Result
Feed v1 NDCG@10 about 0.42 and Recall@10 about 0.68 on the sample holdout. Search v1 NDCG@10 1.00 on curated queries. Recruiters can try frozen feed and search chips on this page. Full training repo stays on request.
Architecture
How the system is shaped. Full implementation stays private.
Step 1
Ingest
Bronze CSV to silver parquet with schema validation and quarantine on bad rows.
Step 2
Features
DuckDB views for item popularity decay, member session stats, and catalog joins.
Step 3
Rank
Feed track: co-occurrence candidates, two-tower retrieval, LightGBM rerank. Search track: BM25 hybrid retrieve, intent classifier, policy filter, LightGBM rerank.
Step 4
Serve
FastAPI with /feed/recommend and /search/rank plus product console. Portfolio demo serves frozen golden outputs on Cloudflare or locally.
Sample holdout metrics (session LOO feed, curated search queries)
RetailRocket-style sample catalog in the portfolio lab. Feed v1 uses candidates, two-tower retrieval, and LightGBM LambdaRank. Search v1 uses BM25 hybrid retrieve, intent rules, policy filter, and LightGBM rerank.
| Track | NDCG@10 | Note |
|---|---|---|
| Feed popularity baseline | NDCG 0.12 | Recall 0.36 |
| Feed v1 | NDCG 0.42 | Recall 0.68 |
| Search BM25-only | NDCG 0.99 | MRR 1.00 |
| Search v1 | NDCG 1.00 | MRR 1.00 |
Algorithm
Two-track discovery with offline eval gates
Train feed and search rankers offline, evaluate with session holdout and curated queries, then serve through a shared catalog registry.
feed_candidates = cooccur(session) + category_pool + popularity
feed_scores = lgbm_rank(two_tower(session), feed_candidates)
search_hits = bm25_hybrid(query) |> policy_filter
search_scores = lgbm_rank(query_features, search_hits)
ship when ndcg@10 beats baseline on frozen splitsKey logic
Compact illustrative snippet (Policy filter before search rerank (illustrative)). Not the full codebase.
def filter_item_ids(item_ids, policy):
blocked = policy.blocked_categories or set()
return [i for i in item_ids if catalog[i].category_id not in blocked]Stack
Try feed and search
Frozen sample catalog from the portfolio lab. Switch between session feed ranking and hybrid search. Full FastAPI serving stack stays on request.
Source code
Full source is available to hiring managers on request. The public page shows architecture, algorithms, and compact proofs only.