Books Deep-Read · ML System Design Interview · Chapter 7
Machine Learning System Design Interview · Ch 7 · Ali Aminian & Alex Xu · 2023
A ticketing app shows you a screen: "this weekend, near you" — a comedy night, a hike, a street market. This chapter is about how that screen gets ordered. What makes it different from recommending films is blunt: these "goods" will not exist in a few days.
Recommending films is like suggesting books in a library that never closes. The books stay on the shelves, and the record of who borrowed what only gets thicker. The thicker it gets, the better the machine knows which book to hand to whom.
Events are not like that. They are a morning market: today's stall goes up today and comes down tonight. When a show first goes on sale, nobody has been to it; by the time enough people have proven it popular, it has already started — or already finished. So the sentence recommendation systems live on — "people with taste like yours went too" — cannot even be spoken here.
The usual method is to look at other people: what did people similar to you also watch, also buy. That method has a precondition — the item must live long enough to be tried by many. Videos, products and songs qualify. Events do not.
The result: a system that only knows how to look at other people knows nothing about the vast majority of events currently on sale. All it can push is the small handful that already caught fire. A newly listed event never gets in front of anyone — and new listings are exactly what the platform adds every single day.
If you cannot accumulate "who went", you switch to a different basis: ask, item by item, about this person, this thing, and this moment. How far from home? Can you walk, or must you drive? Saturday afternoon or Wednesday midnight? Do you normally go out at that hour? How much does it cost? How many of your friends have already signed up? Do you follow the organiser?
That long list of questions is a questionnaire. The system takes a few million past events — their questionnaires and what actually happened — and trains a judge to look at a fresh questionnaire and estimate the chance that this person signs up. It does not know this event; it knows the shape of the form. Exactly like you and the new place on the corner: you have never been, but "800 metres away, serves the food you usually order, three of your friends booked a table" already tells you what you need.
Worth noting: the most useful line on that form is usually not how well the content matches, but whether friends are going. Attending an event is a social act to begin with.
What to remember: this chapter moves the effort from "pick a cleverer model" to "design the questionnaire well". If the form has no line for "how many friends are going", no judge, however sharp, can recover it. And because the market restocks every day, the judge has to go back to school every day too.
"All your friends are going" is the strongest signal and also the strongest bias: it makes the crowded more crowded, and leaves niche events, the ones nobody has heard of yet, even harder to surface.
Event recommendation is hard not because guessing is hard, but because the goods expire. With no history to learn from, all you have left is the specifics of this person, this thing, here and now — which is why the real protagonist of this chapter is not the model, it's how the questionnaire is written.
Want the mechanisms, the notation and the diagrams? → switch to the deep read
On the surface this chapter builds an event recommender. Underneath it is one structural fact forced by item lifespan: the goods here expire. An event lives days to weeks from creation to close, has zero interactions the moment it is listed, and is gone before it accumulates data — so cold start is not an edge case, it is the steady state, and collaborative filtering, which eats interaction matrices, is cut off at the root. What is left is the specifics: this user × this event × here and now. So the chapter shifts its weight from model choice onto feature engineering, and frames the problem as learning to rank (LTR): not "does he like it" but "put this batch of candidates in the right order by registration probability".
This is the sixth of the ten case studies in Part II. It follows Ch6 on video recommendation, where items are long-lived and interactions plentiful, so the protagonist was the split between retrieval and ranking; here items are short-lived and interactions thin, and the protagonist becomes the features. It leads into Ch8 on ad click prediction — also pointwise scoring, but there the score gets billed against, so probability calibration becomes non-negotiable. The real-world counterparts are Meetup, Eventbrite and Facebook Events.
The book's setup is an events platform: a user opens the home page, sees a screen of recommended events, and the business goal is registration conversion — not clicks. Two constraints separate this chapter cleanly from the last one.
One: item lifespan measured in days. A video lives for years after upload and can accumulate millions of views, so the interaction matrix has plenty to chew on. An event lives days to weeks from creation to start, may collect only tens or hundreds of interactions in its entire life, and is delisted permanently afterwards. Put differently: every event is recommended from start to finish while still in cold start, and then it disappears.
Two: positives are extremely rare. Impressions are plentiful, registrations are not. For scale: at a 1% registration rate, a model that always predicts "will not register" is 99% accurate — accuracy is a dead metric here, and that is the starting point of this chapter's evaluation section.
What happens if you ignore all this? A recommender that only reads the interaction matrix knows nothing about most of the events on sale, and can only push the small handful already on fire. The rich get richer, new organisers never get off the ground — and new organisers are precisely the supply the platform adds every day.
The book frames it as a ranking problem: given a "user × event" pair, predict the registration probability P(register | user, event) and sort descending. Labels come for free — impression followed by registration is a 1, impression without one is a 0.
Learning to rank comes in three training units, differing in how much it looks at per step:
The book picks pointwise for pragmatic reasons: simplest to implement, easiest labels, reusable score. A criterion worth taking away: if you care intensely about the order of the top few → pairwise / listwise; if you want engineering simplicity and the score reused elsewhere (billing, thresholds) → pointwise.
Since you cannot ask "who went", you can only ask about this person, this thing, this moment. The book sorts features into four groups, and each group brings out a different encoding technique.
Location. Distance between the venue and where the user usually is, same-city or not, walk score, public transit access. The key technique here is to bucketize and then one-hot — do not feed raw kilometres. People respond to distance as a cliff, not a slope: 3 km and 5 km are barely different, 5 km and 50 km are different worlds. Closer to the real decision than straight-line distance is estimated travel time: 8 km across a river can be further than 15 km within a district.
Time. This group holds the chapter's most characteristic feature: time remaining until the event starts. What makes it special is that the same user–event pair must score differently at different moments — thirty days out and two hours out are two different buying mindsets. Alongside it: duration, day of week, hour of day, and the user's historical attendance times. Weekday and hour come with a trap: they are circular. Sunday 23:00 and Monday 00:00 are adjacent in life and maximally far apart numerically, so they need one-hot or a cyclical encoding, never a raw number.
Social — the most valuable column in this chapter. How many of the user's friends have registered, whether the host is a friend or followed, whether a friend sent a direct invitation, registrations against capacity. Why so strong? Because attending an event is a social act — "three friends are going" often decides attendance more than content match does. Asked in an interview which feature matters most, answer social plus time-remaining and you will not be wrong.
The user and the event itself. Age, gender (bucketized and one-hot); ticket price (free versus paid conversion often differs by an order of magnitude), category, an embedding of the description text, the organiser's historical conversion rate.
The encoding toolkit is four items, each for a different problem: one-hot for low-cardinality categories; bucketize + one-hot for continuous values with a kink; embeddings for high-cardinality IDs; feature crossing for interaction signal. One example makes crossing obvious: very few people will travel 20 km late on a Wednesday, plenty will on a Saturday afternoon — neither distance alone nor weekday alone yields that conclusion, so "distance × weekday" has to be built explicitly.
And here the short lifespan bites again: an embedding for the event ID barely trains, because each ID appears only a few dozen times in its whole life. What does train is the layer above — organiser ID, venue ID, category — because those are reused across events and therefore have enough samples.
Features split by when they are computed. Batch features are precomputed offline and refreshed hourly or daily: the description embedding, the organiser's historical conversion rate, the user's long-term interest profile. Streaming features are computed live at request time, within seconds: has a friend just registered, how many tickets are left, how long until it starts, current device and location.
This chapter cannot avoid streaming features for a blunt reason: its two strongest features are exactly the ones that change. Time remaining moves every minute; friends-registered can increment at any moment. A value computed an hour ago is already wrong by the time the user makes the request.
The engineering cost is that one feature needs two computation paths — historical backfill tables for offline training, a live stream for online serving — and the moment they disagree you have training-serving skew: lovely offline metrics, an inexplicable drop in production.
Look at what you are holding: tens to hundreds of hand-built, tabular, mixed categorical-and-numeric, fairly sparse features. This is GBDT home ground — no normalisation needed, non-linearity and interactions learned automatically, steadier than a neural network on small-to-medium data, and interpretable: feature importances tell you directly which column is doing the work. That matters especially here, because the features you built are your model.
The book offers a ladder: logistic regression (fast, interpretable, but every cross must be hand-built) → decision tree (learns non-linearity, overfits alone) → GBDT (the default) → neural network (worth it once data is large enough, or when you need text embeddings or continual learning).
GBDT has two weaknesses, both amplified by this chapter's nature: it is awkward to update incrementally (new events arrive daily, yet traditionally the whole model is retrained) and it is bad with high-cardinality ID embeddings. So the industrial compromise is usually one of two: GBDT plus frequent retraining (daily, even hourly), or GBDT output fed as a feature into a light neural network.
Evaluation runs on two registers. Offline: with positives around 1%, accuracy has to go, replaced by area under the precision-recall curve for classification quality, and Recall@k / MRR / nDCG for ranking quality — MRR when a request expects a single right answer, nDCG when relevance has grades. Online: click-through rate, registration conversion (the actual business goal), revenue. And if negatives were downsampled during training, the score must be calibrated back to a true probability, or anything downstream involving thresholds, budgets or money will be wrong.
This is the point most easily confused with Ch6. There the first stage was model retrieval — two towers plus approximate nearest neighbours — because a billion videos come with no natural filtering predicate. Here you do not need it: events are tightly bound in space and time. "Has not started yet" plus "within the user's radius" cuts 10⁵–10⁶ on-sale events down to a few hundred or a few thousand, and a ranking model swallows that directly.
So the path is: all on-sale events → rule filter → candidates 10²–10³ → feature assembly (batch + streaming) → ranking model → top-k. Copying the previous chapter's retrieval layer over is a free layer of complexity — and a common way to lose points in an interview.
Finally, retraining must be frequent. The inventory turns over daily; seasons, holidays and per-city event density all move. What the model learned last month may not hold this month. That is a direct corollary of short-lived items.
Table 1 · Video recommendation (Ch6) vs event recommendation (Ch7)
| Video recommendation | Event recommendation | |
|---|---|---|
| Item lifespan | Months to years; interactions thicken | Days to weeks; delisted on expiry |
| Cold start | An edge case, covered by popularity | The steady state, for every item's whole life |
| Main method | Collaborative + content, two towers | Collaborative fails; features only |
| First stage | Model retrieval (two towers + ANN) | Rule filter (time + geo radius) |
| Strongest signal | The user's watch history sequence | Social ties + time left until start |
| Retraining | Daily is fine | Daily to hourly; skip it and you drift |
Table 2 · The three learning-to-rank paradigms
| Pointwise (the book's pick) | Pairwise | Listwise | |
|---|---|---|---|
| Training unit | One sample | One pair | The whole candidate list |
| What it learns | Absolute preference (probability) | Relative order | A list-level metric directly |
| Score meaning | A probability, reusable | Ordinal only | Ordinal only |
| Engineering cost | Lowest; any classifier works | Medium; must build pairs | Highest |
| Weakness | Blind to the rest of the request | Pair count explodes | Slow to train, complex |
Table 3 · The model ladder: why it stops at GBDT
| Logistic regression | GBDT (the book's pick) | Neural network | |
|---|---|---|---|
| Non-linearity, crosses | All hand-built | Learned automatically | Learned, including high order |
| Preprocessing | Normalise and encode | Almost none; eats raw tables | Normalise; embed categories |
| Data needed | Very little | Moderate; steadiest at this size | A lot |
| Interpretability | Best (read the weights) | Good (feature importances) | Poor |
| Incremental learning | Easy | Awkward; retrain wholesale | Easy |
| High-cardinality IDs | Cannot cope | Cannot cope | Embeddings are its strength |
Two practical criteria that are not in any table: features matter far more than the model — adding a "friends already registered" column usually beats swapping GBDT for something fancier; and cold start here is mostly not a modelling problem, it is handled by rules and product moves: give a new user same-city popular events with high fill rates, and let the first few clicks converge fast.
The shape generalises well beyond events: anywhere items have an expiry date and start life in cold start, this chapter applies. Ticketing and events platforms (Meetup, Eventbrite, Facebook Events) are the direct case; further out, limited-time coupons, distressed airline and hotel inventory, live-stream "going live" alerts, "closing soon" job recommendations, same-day restaurant availability — all share one property: the interaction matrix never warms up before the item is gone.
Interviews press on three places: why collaborative filtering does not work here (say "item lifespan" out loud rather than reciting definitions), which features matter most and why (social ties and time remaining), and which offline metric to use (start by explaining why accuracy is dead).
1. The goods in this chapter expire: event lifespans are measured in days and interactions are zero at listing, so cold start is the steady state, not an edge case.
2. Collaborative filtering is therefore cut off at the root — the interaction matrix never thickens — leaving only the features of this user × this event × here and now.
3. Framed as learning to rank, and the book picks pointwise: predict P(register | user, event) and sort descending. Simple, labels for free, the score is a reusable probability; the cost is blindness to the rest of the request.
4. Four feature groups: location, time, social, and the user and event themselves. The two strongest are social ties and time left until start.
5. Four encodings: one-hot for low cardinality, bucketize-then-one-hot for kinked continuous values, embeddings for high-cardinality IDs, feature crossing for interaction signal. Weekday and hour are circular — never raw numbers; and the event-ID embedding never trains, while organiser / venue / category does.
6. The strongest features happen to be streaming ones (time remaining, friends registered), so batch and streaming paths must both exist — and the moment they disagree you have training-serving skew.
7. The model stops at GBDT: home ground for tabular heterogeneous features, interpretable, steadiest at this data size; its weakness is incremental updating, which frequent retraining covers. Drop accuracy in evaluation, use PR-AUC plus Recall@k / MRR / nDCG, and watch registration conversion online.
8. The first stage of the serving path is rules, not a model: space-time predicates take 10⁵–10⁶ down to 10²–10³, which the ranking model swallows directly.