ML System Design · Module 38 of 47 · 12 concepts · about 13 min

Design: Similar Listings for Holiday Rentals

A complete design for the 'similar homes' row on a holiday-rental listing page: learning listing embeddings from browsing sessions the way word embeddings are learned from sentences, using bookings as a stronger signal, sampling negatives within the same market, handling brand-new listings, and serving nearest neighbours that respect dates, guests and availability.

At work: Asked as 'design similar listings', 'more like this' or 'related products'. It is the classic case of learning item embeddings from user behaviour, with a well-documented public example.

Requirements

What it is

Staybook, a made-up holiday-rental marketplace, shows a row of similar homes on each listing page. Clarify:

  • catalogue: about 5,000,000 active listings worldwide, each unique (no two homes are the same item);
  • context: the guest has a destination, dates and number of guests;
  • goal: help guests who are not sure about this home find one they book; more bookings from the row;
  • latency: the row loads with the page, within about 100 ms;
  • constraints: every suggestion must be available for the guest's dates and fit the group; and in the same area as the home they are viewing.

Why it matters

Similarity here is subtle.

  • Two flats with identical bedroom counts can feel completely different (a beach hut and a city loft).
  • What guests consider similar is best learned from what they browse together, not from listed attributes alone.

In the real world: Airbnb reported that embedding-based similar listings raised the click-through rate of its similar-listing carousel by about 21% in an A/B test, compared with the previous approach.

Defining similarity by attributes only (same price band, same bedrooms). It misses style, view and atmosphere, which guests care about and rarely describe.

The core idea: listings as words, sessions as sentences

What it is

Learn a vector for each listing from browsing sessions, the way word2vec learns word vectors from sentences:

  • a session is the sequence of listings one guest clicks while searching (split when there is a long gap, for example 30 minutes);
  • listings that appear close together in many sessions get similar vectors;
  • the skip-gram objective: for each listing, predict the listings near it in the session.

Why it matters

Guests implicitly label similarity every time they compare homes.

  • Millions of sessions capture subtle shared qualities (houseboats with houseboats, treehouses with treehouses) that no attribute field records.
  • The resulting vectors make 'similar' a nearest-neighbour lookup (module 13).

In the real world: Airbnb's KDD 2018 paper trained 32-dimensional listing embeddings this way on hundreds of millions of click sessions; it won that year's best paper award in the applied track.

Treating a whole day of browsing as one session. A guest planning a beach trip in the morning and a city break in the evening would teach the model that beach huts resemble city lofts.

Bookings as a stronger signal

What it is

A click shows interest; a booking shows a decision. Use it:

  • for sessions that end in a booking, add the booked listing as a context for every listing in the session, not just its neighbours;
  • this pulls all the homes the guest compared towards the one they finally chose;
  • sessions without a booking still contribute through ordinary neighbours.

Why it matters

Embeddings learned only from clicks capture what looks similar; adding bookings captures what guests treat as alternatives to book.

  • That is exactly what a 'similar listings' row should show.

In the real world: The Airbnb paper calls this treating the booked listing as a 'global context' and reports it improved how well similar listings predicted the eventual booking.

Visual example

Computed

One session L1 → L4 → L2 → L9 → L5, ending in a booking of L5. Window of 1 on each side. Every listing also learns from the booked one.

Positive (listing, context) pairs for skip-gram training
listingneighbours in the windowglobal context (booked)
L1L4L5
L4L1, L2L5
L2L4, L9L5
L9L2, L5L5
L5L9— (it is the booking)

Training only on booked sessions. They are a small share of all sessions; you would throw away most of the signal about similarity.

Negatives from the same market

What it is

Skip-gram also needs negatives: listings that should be pushed apart. Two kinds:

  • random negatives from the whole catalogue: mostly in other cities, so the model easily learns 'different city, different listing' and little else;
  • same-market negatives: random listings from the same destination as the target, so the model must learn what distinguishes homes within a place.

Why it matters

Sessions are almost always within one destination, so positives are always local.

  • With only global negatives, the model mostly learns geography.
  • Same-market negatives force it to learn style, size and price differences within a city, which is the similarity guests care about.

In the real world: The Airbnb paper added negatives sampled from the same market as the central listing for this reason.

# Skip-gram with negative sampling, for one (target, context) pair.
def pair_loss(v_target, v_context, v_negatives):
    pos = -log_sigmoid(dot(v_target, v_context))
    neg = -sum(log_sigmoid(-dot(v_target, v_n)) for v_n in v_negatives)
    return pos + neg

negatives = random_listings(k=5) + random_listings_in_market(target.market, k=5)

Only random negatives. The embeddings separate Goa from Manali perfectly and cannot tell a party villa from a quiet cottage in the same town.

New listings: cold start

What it is

A listing created yesterday has no sessions, so no learned vector. Give it one from similar existing listings:

  • find listings nearby (for example within a few kilometres), of the same type (entire home, private room) and similar price;
  • set the new listing's vector to the average of a few of their vectors;
  • replace it with a learned vector once it appears in enough sessions.

Why it matters

New hosts need visibility to get first bookings and reviews; a reasonable vector puts them in similar rows from day one.

  • Location, type and price explain a large part of what guests compare.

In the real world: The Airbnb paper initialised new listings by averaging the embeddings of three nearby listings of the same type and price range, and reported this covered most new listings well.

Leaving new listings out of the index until they have history. They then never appear in similar rows, so they never gain the history needed.

Practise it: Design a Demand Forecasting Platform, Design a Real-Time Anomaly Detection System, Design a Recommendation System, Design a Model Serving Platform, Design a Personalized News Feed, Design a Search Ranking System

Retrieval and filtering

What it is

At page load, for the listing being viewed:

  • look up its vector;
  • find nearest neighbours in the same market (a per-market index keeps the search small and local);
  • filter by availability for the guest's dates, guest capacity, and any hard search filters the guest set;
  • keep the top few hundred for ranking.

Why it matters

Similarity without availability is useless: the most similar home is often booked for those dates.

  • Fetching extra neighbours before filtering ensures enough remain (module 13's post-filtering trap).

In the real world: Holiday-rental search keeps per-market indexes and checks availability calendars as a hard filter, because availability changes daily.

Post-filtering only the top 20 neighbours. In a busy season most are unavailable and the row shows three homes, or none.

Practise it: Design a Recommendation System, Improve a Low-Recall Model, Design a Search Ranking System

Ranking the row

What it is

A ranking model (boosted trees or a small neural network) orders the filtered neighbours, using:

  • similarity to the viewed listing (embedding cosine);
  • similarity to the guest's session: average similarity to listings they clicked, and dissimilarity to listings they skipped;
  • listing quality: reviews, response rate, past booking rate;
  • price and location relative to the viewed listing and the guest's search;
  • label: booked (strongest), clicked, shown only.

Why it matters

Pure similarity can show near-duplicates of a listing the guest is hesitant about.

  • Session features personalise in real time: if the guest keeps clicking homes with pools, the row leans towards pools.

In the real world: Airbnb described using real-time similarity between candidate listings and a guest's recent clicks and skips as features in search ranking, built from the same embeddings.

Showing the closest neighbours only. They may be the same host's identical flats; mix in some variety and cap listings per host.

Practise it: Design a Recommendation System, Design a Personalized News Feed

Serving and freshness

What it is

The system has offline and online parts:

  • daily: retrain embeddings on recent sessions; rebuild per-market indexes; initialise vectors for new listings;
  • precompute: top few hundred neighbours per listing per market, refreshed daily;
  • online: availability and capacity filter on the precomputed list, then rank with session features;
  • live: the guest's clicks and skips in this session update their session features.

Why it matters

Precomputing neighbours makes the row a fast lookup plus filtering and ranking.

  • Daily retraining keeps embeddings current as new listings and seasons change behaviour.

In the real world: Precomputed neighbour lists with live availability filtering are a common pattern for 'similar items' features at marketplaces.

Visual example

Similar homes

Learn daily; filter and rank live.

From sessions to a row of homes

  1. Daily

    SessionsClicks split at 30-minute gaps
  2. Train embeddingsBooked context; same-market negatives
  3. Cold startNew listings: average of neighbours
  4. IndexNearest neighbours per market
  5. On each page view

    FilterDates, guests, hard filters
  6. RankSimilarity, session fit, quality

Comparing vectors from yesterday's model with vectors trained today. Rebuild every vector and index together after each retrain (module 13).

Practise it: Design an Image Search System, Design Feature Monitoring, Diagnose Training-Serving Skew, Debug a Production ML Model, Design a Model Serving Platform, Design a Personalized News Feed, Design an ML Feature Store

Evaluation

What it is

Offline and online:

  • offline: for sessions that ended in a booking, take a clicked listing, rank candidate listings by similarity to it, and measure how high the eventually booked listing ranks (the earlier in the session, the harder);
  • sanity checks: do nearest neighbours share type, price band and location? do unusual homes (treehouses, boats) cluster together?
  • online: click-through and bookings from the row; share of guests who book a listing first seen in the row;
  • guardrails: overall bookings, cancellations, host concentration.

Why it matters

The offline test mirrors the product question: does similarity to what a guest looked at predict what they will book?

  • Sanity checks catch embeddings that have learned only geography.

In the real world: The Airbnb paper evaluated embeddings by the rank of the eventually booked listing among search results re-ranked by similarity to the user's latest click.

Visual example

Choices

Each was a deliberate response to a failure of the simpler version.

Design choices and what each fixes
choicewhat goes wrong without it
Split sessions at long gapsUnrelated trips teach false similarity
Booked listing as global contextEmbeddings capture looks, not real alternatives
Same-market negativesEmbeddings learn only geography
Averaged vectors for new listingsNew hosts never appear in rows
Availability filter before rankingRows full of unavailable homes

Judging embeddings by how pretty the nearest neighbours look for a few famous listings. Measure on thousands of sessions.

Practise it: Design a Large-Scale Classification Platform, Design a Predictive Maintenance System, Design a Real-Time Anomaly Detection System, Design a Recommendation System, Diagnose Training-Serving Skew, Improve a Low-Recall Model, Design a Search Ranking System

Sources and further reading

What it is

Public work this design draws on:

  • Grbovic and Cheng, 'Real-time Personalization using Embeddings for Search Ranking at Airbnb', KDD 2018: session-based listing embeddings, booked-listing context, market negatives, cold start;
  • Mikolov et al., 'Distributed Representations of Words and Phrases and their Compositionality', 2013: skip-gram with negative sampling;
  • Grbovic et al., 'E-commerce in Your Inbox: Product Recommendations at Scale', KDD 2015: item embeddings from purchase sequences ('prod2vec');
  • Airbnb's engineering blog posts on embedding-based retrieval for search.

Why it matters

This is one of the clearest public case studies of learning item embeddings from behaviour, and interviewers often know it.

In the real world: Explaining why same-market negatives are needed is a reliable way to show you understand embeddings beyond the basics.

Interview questions: the similar listings design

What it is

The questions interviewers ask about the similar listings design, from the first screening call to the senior round. Cover the answer, say yours aloud, then compare.

Why it matters

Reading an idea and explaining it are different skills.

  • Each answer below is the two or three sentences an interviewer is listening for.
  • The reasoning behind each one is in the cards above. If an answer surprises you, go back to that card.

In the real world: Marketplace interviews often use this question to test embedding intuition: sessions as sentences, negatives and cold start.

Q: How would you learn what 'similar' means for homes?

From browsing sessions: listings clicked near each other in a session get similar vectors, trained with a skip-gram objective as in word2vec.

Q: How do bookings improve the embeddings?

For sessions that end in a booking, the booked listing is added as context for every listing in the session, pulling compared homes towards the chosen one.

Q: Why sample negatives from the same market?

Positives are almost always local, so global negatives only teach geography; same-market negatives force the model to learn differences within a destination.

Q: How do you handle a new listing?

Average the vectors of a few nearby listings of the same type and price, and replace it with a learned vector once it has enough sessions.

Q: What filters are needed at serving?

Same market, availability for the guest's dates, guest capacity and the guest's hard search filters, after fetching enough neighbours.

Q: How would you evaluate offline?

Check how highly the eventually booked listing ranks by similarity to listings clicked earlier in booked sessions, plus sanity checks on neighbours.

Defining similarity only by listing attributes.

Exercise: learn item embeddings from sessions

What it is

A short build that uses this module's ideas. Write it yourself before looking anything up; the checks at the end tell you whether it works.

Why it matters

An idea you have only read fades in a week.

  • Building it once, even in fifty lines, is what makes it yours.
  • Interviewers can tell the difference between someone who has read about a loop and someone who has debugged one.

In the real world: This build mirrors a famous public system closely enough to discuss confidently in an interview.

Your task. Train item embeddings from browsing sessions and use them for 'similar items', with market-aware negatives and cold start.

Steps

  1. Use a public session dataset (for example an e-commerce clickstream dataset with session IDs, or MovieLens ratings ordered by time as pseudo-sessions).
  2. Split sessions at 30-minute gaps; build skip-gram training pairs with a small window.
  3. Train embeddings with gensim's Word2Vec (skip-gram, negative sampling).
  4. Evaluate: for sessions ending in a purchase, rank items by similarity to an earlier click and record the rank of the purchased item.
  5. Group items into 'markets' (categories) and add same-category negatives by training a small custom model; compare the evaluation.
  6. Give items absent from training an averaged vector from similar items, and test whether they now appear in sensible neighbour lists.

You are done when

  • Embedding neighbours beat a 'same category, most popular' baseline on your ranking test.
  • Same-market negatives improve within-category distinctions.

Stretch. Add the purchased item as a global context for every item in purchasing sessions and measure the change.

Practise it: Design a Recommendation System