In this article
Before you start
This page is one step of the recommendation system design learning path, and it assumes you have met the general shape of a recommender.
Why interviewers ask this
A design that scores every user against every item on one big model fails at the first scale question, so this prompt tests whether you know the funnel. Candidates report being given versions of it for a food-delivery app, a dish recommender, a marketplace product search and a new-user feed. It sits inside the wider machine learning system design round.
A weak answer names a model and stops. A strong answer separates stages, says why each exists, names the hard constraints of the domain (place, opening hours, stock), and has a plan for users and items with no history. A Staff-level answer also chooses the metric for each stage, because retrieval and ranking are judged differently, and names the guardrails that stop a click-greedy model from hurting delivery time or small sellers.
Food-delivery and e-commerce recommendations from first principles
- Candidate retrieval
- Candidate retrieval is the first stage of a recommender that narrows a catalog of millions of items to a few hundred plausible ones using a cheap model, so that a heavier model can score only that short list.
- Hard filter
- A hard filter is a rule that removes an item from consideration before any model scores it, such as a restaurant that is closed or outside the delivery area, so no score can bring it back.
- Slate
- A slate is the final ordered list of items shown to one user on one screen, after ranking and after rules such as variety and new-item slots are applied.
In plain words
Picture a friend who knows your neighborhood and is asked, "Where should I order from?" The friend first drops places that are closed or too far. Then the friend thinks of a short list that fits your taste. Then the friend sorts the list by the mood of the evening and mixes in one new place. The analogy breaks in one spot: a friend knows you, while a new app often does not, which is the cold start problem below.
Precisely, a recommender maps each user (or request) and each item to an embedding in one shared space and returns items whose embeddings are close, which is how Google's course describes candidate generation as of its August 2025 update. Closeness is measured with cosine, dot product or Euclidean distance. Production systems split the work in two: Covington et al. (2016) describe a deep candidate generation model followed by a separate deep ranking model, the classic two-stage design.
Step 1: Apply hard filters for place and time
Hard filters remove closed and distant stores before any model runs. Food delivery is geography-bound: Uber's engineers note that the user would not order from a store far from their location, so candidates are limited by distance.
Input: the user's location, the time and the full catalog. Output: the stores that are open now and can deliver to this address, in practice a few thousand. Opening hours, delivery area and whether a dish is in stock are rules, not predictions, so they belong in a filter and not in a learned score. A model that is allowed to recommend a closed restaurant will do so whenever the restaurant is popular. In e-commerce the same step removes out-of-stock products and items that cannot ship to the address. You now know which items are allowed; the next step chooses which of them are worth scoring.
Step 2: Retrieve a few hundred candidates with a two-tower model
Retrieval cuts the stores that pass the filters to several hundred candidates, using a model cheap enough to score each of them in a dot product. A two-tower model is a pair of networks, one for the user and one for the item, whose output vectors are compared with a dot product; the two-tower model page covers training in depth.
Uber describes precomputing every store embedding in batch and indexing it for approximate nearest-neighbor search. Approximate nearest-neighbor search is a lookup that checks only a small part of the index and may miss a few true top items in exchange for speed; see embeddings and vector search. The cost then drops from one deep-model call per user-store pair to one batch pass over the stores, one real-time call per request and cheap dot products. Recall at K is the share of the items the user actually wanted that appear in the top K candidates, and it is the metric for this stage.
Step 3: Cover users and restaurants with no history
Cold start is the situation in which a user or an item has too little behavior for a model to place it in the embedding space. A system needs a fallback for both sides, and the interviewer's next question is almost always about it. The cold start problem page gives the full toolbox.
For a new user, fall back on what you do know: location, time of day, and the popularity of open stores nearby, optionally refined by one or two onboarding choices such as cuisines. Uber Engineering reports that describing an eater by a time-sorted list of previously ordered stores reduced the model size by 20 times and partly helped eater cold start. For a new restaurant, give the item tower content features such as cuisine, menu text and price, so it has a vector before its first order. Covington et al. (2016) name freshness as a core challenge for the same reason. Finally, reserve a slate position for newcomers so they collect data.
Step 4: Rank the candidates, then re-rank into a slate
A ranking model is a heavier model that scores each retrieved candidate for one user using rich, current features, and it orders the short list. Because only hundreds of candidates reach it, it can read price, rating, distance, estimated delivery time and context. Predicting both click and order with one network is the subject of multi-task ranking, and a model that reads user and item together is the idea behind a cross-encoder reranker.
A re-ranker then turns the ordered scores into the slate: it removes near-duplicates, spreads cuisines or brands, applies the new-store slots from Step 3 and enforces guardrails such as a delivery-time cap. A two-tower model can also serve as the final ranking layer when per-item online features are too costly, as Uber did for a grocery item feed. A ranking model orders the candidates and a re-ranker builds the slate.
Step-by-step description
- Closed and distant stores are removed first.
- Two towers keep a few hundred candidates.
- Fallbacks cover users and stores with no history.
- The ranker orders, the re-ranker builds the slate.
- Hard filters remove closed and distant stores before any model runs.
- Retrieval cuts the stores that pass the filters to several hundred candidates.
- A ranking model orders the candidates and a re-ranker builds the slate.
Knowing it is half the job. Saying it is the other half.
Interview Clozo is an AI interview copilot for real interview rounds: it hears the question and puts a strong answer on your screen, and you say it in your own words. See the features or how it works.
Start Free Trial →Worked example
Take three million stores and a thousand requests per second; both numbers are illustrative, not Uber's. Scoring every user-store pair with a deep model would need three billion model calls per second. The two-tower design needs one thousand query-tower calls per second, plus three million item-tower calls each time the store embeddings are refreshed.1
Now follow one request down the funnel. Hard filters keep 6,000 stores, retrieval keeps 500, the ranker keeps 50 and the first screen shows 20 (all illustrative). The ranker then makes 500,000 calls per second, which is 6,000 times fewer than scoring every pair.1 Without a geo shard, approximate nearest-neighbor (ANN) search that visits 0.5% of the 3,000,000-store index (illustrative) touches 15,000 store vectors per request, about 1,920,000 multiply-adds at 128 numbers per vector, against 384,000,000 for brute force over the whole index.1 Once the geo filter cuts the set to 6,000 stores, exact scoring costs only 768,000 multiply-adds, so ANN pays off mainly for national catalogs such as e-commerce.1
| Stage | Items in (illustrative) | Items out | Judged by |
|---|---|---|---|
| Hard filters | 3,000,000 | 6,000 | rules, no model |
| Retrieval | 6,000 | 500 | recall at K |
| Ranking | 500 | 50 | normalized discounted cumulative gain (NDCG), click and order quality |
| Re-ranking | 50 | 20 | variety, guardrails, A/B test |
NDCG is a ranking score that rewards putting relevant items near the top and divides by the best possible order. For a ranked list of ten with relevant items at positions 2, 4 and 7, and a fourth relevant item never retrieved, recall at 5 is 0.5, recall at 10 is 0.75 and NDCG at 5 is 0.4144.1
Cold start gets a toy case. Five stores have a popularity, a distance and an open flag, and the score is popularity (scaled) times a distance decay times open. Store B scores 0.4553, A 0.4228, E (a new store) 0.2348, C (most ordered, 6 km away) 0.1429 and D (closed) 0. Reserving the second slot for the new store gives the slate B, E, A, C, D.1
Text description of the diagram
- Store B scores 0.4553, A 0.4228 and E 0.2348.
- Store C scores 0.1429 and closed store D scores 0.
An A/B test is a live experiment that shows two versions to different random groups. Say 420 orders per 10,000 sessions for control and 460 for the variant (illustrative): 4.2% against 4.6%, a relative lift of 9.52%, which still needs a significance check.1
Trade-offs and edge cases
Retrieval is judged by recall at K with K in the hundreds, not by precision at the top, as Uber states: a store missed here can never be ranked. In-batch training samples popular items as negatives too often. The logQ correction is a term that subtracts the log of an item's sampling probability from its score, as proposed by Yi et al. (2019), and the Uber Engineering post on two-tower embeddings reports, for Uber's global two-tower model, that it improved recall at 500 from 89% to 93%. At sampling probabilities of 0.01 and 0.0001 (illustrative), the popular item's score drops by 4.6052 more.1
Food delivery and e-commerce share the funnel but differ in constraints. Food delivery filters by distance and open hours and has a catalog that changes by the hour. E-commerce adds a huge long tail and relations between items, such as substitutes and complements. Item-to-item similarity of the "bought together" kind suits it.
Text description of the diagram
- Food delivery filters by distance and open hours.
- E-commerce adds substitutes and complements.
Edge cases: a store that closes mid-session must disappear without a model retrain; a click-greedy ranker can favor slow delivery or crowd out small sellers, so add guardrails; one global model is simpler to maintain than one model per city, and Uber Engineering describes moving from many city-level models to one global model.
Language models can also be used alongside two-tower retrieval; the design of language models inside a recommender covers where they fit.
How does an e-commerce recommender differ from food delivery?
An e-commerce recommender uses the same funnel as food delivery but different retrieval signals and freshness rules. For product search, the query text enters the user tower, so retrieval is conditioned on what the shopper typed as well as on history. For "bought together" shelves, item-to-item retrieval finds products that co-occur in orders with the one being viewed. Substitutes (another brand of the same item) suit a product page where the shopper is still deciding, while complements (a case for a phone) suit the cart. Stock and price change constantly, so availability is a hard filter and price is a fresh ranking feature. Inside one restaurant, the item is a dish, and the filter is menu availability right now.
How to answer it in an interview
How would you design recommendations for a food-delivery app?
I would build a funnel. First, hard filters for distance and opening hours. Then a two-tower retrieval model, with store embeddings precomputed and searched by approximate nearest neighbors, to get a few hundred candidates, judged by recall. A ranking model scores those with rich features such as price, rating and delivery time, and a re-ranker adds variety and guardrails. For new users I fall back on nearby popular open stores, and new restaurants get content features and a reserved slot.
The spoken structure: say the funnel, name the hard constraints, give each stage its metric, then end on cold start.
Common mistakes
- "One big model scores every restaurant for every user." (wrong) That costs a model call per pair. (right) "I retrieve a few hundred candidates cheaply, then rank only those."
- "The model will learn that closed restaurants are bad." (wrong) A popular closed store keeps winning. (right) "Opening hours and delivery area are hard filters."
- "Retrieval should maximize precision at the top." (wrong) Ranking fixes the order. (right) "Retrieval is judged by recall at K."
- "A new user gets a blank page." (wrong) The first session decides retention. (right) "Show nearby popular open stores, then learn from the first clicks."
Follow-up questions
How do you make a restaurant recommendation list for a user without prior data?
Use context and popularity: nearby open stores ranked by recent orders and distance, optionally sharpened by one or two cuisine choices. Learn from the first clicks and switch to the personalized funnel as history grows.
What happens when a brand-new restaurant joins?
The item tower scores it from content features, and a reserved slate slot shows it to users whose embedding is nearest the store's content-based vector, within its delivery area, so it earns its first orders. Without that slot it never gets the behavior data the model needs.
Which metrics would you choose to evaluate a restaurant or dish recommender?
Use recall at K for retrieval and NDCG for ranking on held-out logged data, then an A/B test on order conversion with guardrails such as delivery time and seller diversity.
How would you design a conversational recommender that combines chat, retrieval and a database?
Let a language model turn the chat into a structured query (preferences plus hard filters), run the same retrieval and ranking funnel against the catalog database, and let the model explain the top results from the retrieved rows. This is retrieval-augmented generation (RAG), with metadata filters doing the work of Step 1.
Why use a two-tower model for retrieval and not for everything?
A two-tower model cannot capture fine user-item interactions because its towers meet only at a dot product. Uber did use it as a final ranking layer, but only where per-item online features were too costly.
Should you train one model per city?
Usually not: per-city models multiply maintenance, and Uber Engineering describes moving from many city-level models to one global model. Keep geography as a filter and a feature instead.
- Recommendations at marketplace scale are a funnel: filters, retrieval, ranking, re-ranking.
- Closed, distant or out-of-stock items are removed by hard filters, never left to a model.
- A two-tower model precomputes item embeddings and serves them with approximate nearest-neighbor search.
- Judge retrieval by recall at K and ranking by NDCG, then confirm with an A/B test.
- Plan for cold start on both sides: context for new users, content features and reserved slots for new items.
Sources
- Innovative Recommendation Applications Using Two Tower Embeddings at Uber — Uber Engineering Blog, 14 Apr 2026
- Sampling-Bias-Corrected Neural Modeling for Large Corpus Item Recommendations — Google Research (Yi et al., RecSys 2019), 16 Sep 2019
- Candidate generation overview (Recommendation Systems course) — Google for Developers, 25 Aug 2025
- Deep Neural Networks for YouTube Recommendations — Google (Covington, Adams, Sargin; RecSys 2016), 15 Sep 2016