Books Deep-Read · ML System Design Interview · Ch 2
Machine Learning System Design Interview · Ch 2 · Ali Aminian & Alex Xu · 2023
You spot a pair of shoes on the street. You can't name the brand and you can't describe the style, so you snap a photo, drop it into a shopping app, and it hands you a dozen pairs that look almost identical. That's search by image. This chapter walks through building that whole system from nothing — not one model, the entire thing.
You probably assume the machine understood the picture: ah, a white sneaker. It does no such thing. What it does is squash every picture into a string of numbers — think of it as giving each picture a set of map coordinates. And then the fuzzy question “find me similar pictures” becomes a grade-school geometry question: who is standing nearest?
Search used to run entirely on words. But the picture in your hand has no words attached. “Pale grey, three diagonal stripes near the toe, wavy sole” — could you even type that? And if you did, would the search box know what to do with it? Visual likeness doesn't translate into words. Then there's the volume: a serious image library holds hundreds of millions, even billions of pictures. Even if comparing one takes the blink of an eye, going through them one at a time takes you into next year.
Three moves, each more important than the last.
Speed is bought by giving up the guarantee of finding the single closest picture — it only digs through a few districts, and every so often the truly closest one is sitting in a district nobody opened.
The secret of search-by-image isn't teaching a machine to understand pictures. It's turning every picture into a point on a map so that “alike” becomes “nearby” — and everything after that is the engineering of finding the nearest few points among billions, fast and cheap.
Want the mechanisms, the notation and the diagrams? → Switch to the deep read
The book's first case study, and what it really teaches is a problem transformation. Search-by-image looks like “make a model judge whether two images are alike”; the actual solution is representation learning — encode every image into a fixed-length vector so that visually similar becomes close in vector space. Once that transformation lands, the battleground moves off the model and onto retrieval: how do you find the nearest few dozen among a billion vectors in milliseconds?
This is the first of the ten case studies in Part II of Machine Learning System Design Interview, and the first full run of the seven-step framework from Ch 1. It opens the book's single most reused skeleton — encode into vectors, retrieve with ANN, then re-rank — which Ch 4 (YouTube video search) and Ch 9 (similar listings) both inherit with a different modality bolted on. In the real world it maps to Pinterest Lens, Google Lens and Alibaba's image search.
A user has an image and wants “things that look like this”, but cannot produce a keyword. Text search indexes words, and visual likeness does not translate into words — “three diagonal stripes near the toe” is neither writable nor matchable.
The second pain point is scale, and it bites harder. Take a library of 1 billion images, each encoded as a 256-dimensional float32 vector (float32 = 4 bytes per number): the vectors alone are 10⁹ × 256 × 4B ≈ 1 TB, and one exact search means computing the distance from the query to all billion — roughly 2.56 × 10¹¹ multiply-adds. Even at 10¹¹ operations per second that is several seconds per query, while the product needs p99 < 100ms. Without solving this you have built a demo that works on a hundred thousand images.
The most natural first model is a binary classifier: feed in two images, output alike / not alike. Its fatal flaw isn't accuracy, it's the shape of the compute — answering one query means running a forward pass against every image in the library, a billion of them. That road does not exist in engineering terms.
The book splits it in two instead. Train an encoder; encode every library image offline, once, and store the vectors. At query time encode exactly one image, then do a vector search. The same semantic problem, re-modelled, goes from “a billion inferences per query” to “one inference plus one vector lookup”. That is the real lesson here: in ML system design the biggest performance wins usually come from reframing the problem, not from optimising the model.
Contrastive learning needs a tuple of (query image, 1 positive, n negatives). Negatives are easy — sample randomly from the library. Positives are the hard part, and the book gives three routes, each with a price (see Table 1 below): human annotation is accurate but expensive; data augmentation (rotate, crop, recolour the query image and call the result a positive) is free and unlimited, but the model learns “different renderings of the same photograph”, not “the same kind of object”; user interaction (whatever a user clicked after searching with this image counts as a pair) is plentiful and naturally aligned with the business, which is why the book makes it the workhorse — at the cost of noise and exposure bias.
The mechanism is plain. The query and every candidate (1 positive plus n negatives) pass through the same encoder with shared weights and each comes out as a vector. Compute the similarity between the query vector and each candidate vector — usually just a dot product. Push those n+1 similarities through a softmax to get probabilities, then use cross-entropy to drive the probability of the positive towards 1.
The intuition: every training step pulls the positive a little closer and pushes the n negatives a little further away. After hundreds of millions of steps the whole vector space has been combed into clusters that follow visual semantics. The count of negatives n is an important dial — a larger n gives a richer “push away” signal and trains better, at a memory and compute cost that grows linearly in n.
The system lands as two independent pipelines, and that is the architectural skeleton of the whole chapter.
The indexing pipeline (offline) runs the entire library through the encoder and loads the vectors into an index; new uploads arrive incrementally. Being batch work, slowness is tolerable — but it carries a hidden constraint: change the encoder version and every vector in the library must be recomputed. Re-encoding a billion images is a multi-day job, which puts a hard ceiling on how often the model can be iterated.
The prediction pipeline (online) runs query image (with optional user crop) → preprocessing (resize to a fixed size such as 224×224, normalise pixel values) → encoder produces a vector → ANN retrieves top-k candidates → re-ranking service. Re-ranking is the step most often skipped, and it decides whether the thing can ship: among the “k most similar” that ANN returns are exact duplicates, policy-violating content, images their owners marked private, and posts from accounts this user has blocked. Vector distance stops none of them; only business rules in the re-ranking layer do.
Exact search is O(N×D) for N vectors of D dimensions, which is out at billion scale. The book sorts ANN into four families: trees (recursively partition the space into cells — Annoy), locality-sensitive hashing (LSH) (design hashes so that nearby vectors are likelier to collide into the same bucket), clustering / quantisation (k-means the library into tens of thousands of clusters, scan only the nearest few, and compress each vector down to a code of a few dozen bytes), and graphs (wire the vectors into a navigable neighbour graph and greedily walk towards closer neighbours — HNSW). The libraries it names: Meta's Faiss, Google's ScaNN, Spotify's Annoy.
The one line worth saying out loud in an interview: ANN metrics are always a triple — recall, QPS/latency, and memory footprint. None of them means anything alone. “We hit 99% recall” is worthless if the price was scanning half the library.
The book rules candidates out one at a time, and that passage is a good metrics lesson in itself. MRR (the reciprocal rank of the first hit) throws away every hit after the first — wasteful when the product is supposed to return a whole screen of similar images. recall@k needs to know how many relevant images exist in the entire library, and for visual similarity that denominator is simply unknowable. precision@k counts how many of the top k are right while ignoring order entirely, treating rank 1 and rank 10 as equals. nDCG handles graded relevance (“somewhat similar” versus “very similar”) but demands graded ground-truth labels, which are expensive. That leaves mAP: with binary relevance it counts both how many you hit and how high you ranked them, which makes it the right fit here.
Online metrics go back to the business: click-through rate on the suggested images, and average time users spend on them.
Table 1 · Where positives come from (this decides what “similar” ends up meaning)
| Source | How it is built | Cost / risk |
|---|---|---|
| Human annotation | Annotators judge whether two images are similar | Highest quality; slow and expensive, does not scale — even a million pairs is a large investment |
| Data augmentation | Rotate, crop, recolour the query image and use the variants as positives | Free and unlimited; but it learns “distortions of one photograph”, not “the same kind of object” — built on this alone, the system only finds near-duplicates |
| User interaction | Whatever the user clicked after searching with this image counts as a pair | Plentiful and aligned with the business; costs you noise (misclicks) and exposure bias — an image never shown can never earn a positive label, so the system calcifies over time |
Table 2 · Four ANN families and what each one trades
| Method | Mechanism in one line | What you gain / pay |
|---|---|---|
| Trees Annoy | Recursively cut the vector space into cells; a query only descends into the relevant ones | Fast to build, simple to implement; degrades as dimensionality rises (in high dimensions the cuts barely separate anything) — 256 dims is already a strain |
| LSH | Hash functions built so that nearby vectors are likelier to land in the same bucket | Theoretical guarantees, easy to distribute; high recall requires probing many hash tables, driving up both memory and latency |
| Clustering / quantisation Faiss IVF-PQ | k-means the library into tens of thousands of clusters, scan only the nearest few, compress vectors into short codes | By far the best memory compression (1 TB down to tens of GB), making billion scale viable on one machine; costs accuracy to quantisation error, and the clustering must be rebuilt periodically as the data drifts |
| Graphs HNSW | A layered neighbour graph; start at an entry point and greedily hop towards closer neighbours | Usually the lowest latency at equal recall; costs the most memory (the edges must be stored) and makes inserts and deletes expensive, so it suits libraries that don't churn |
Table 3 · Picking the offline ranking metric (the book's elimination process)
| Metric | What it measures | Why it does or doesn't fit |
|---|---|---|
| MRR | Reciprocal rank of the first hit | Uses a single hit and discards the rest — but search-by-image should return a whole screen of similar images |
| recall@k | Share of relevant items covered in the top k | The denominator is “all relevant items in the library”, and for visual similarity that number is unknowable |
| precision@k | How many of the top k are right | Ignores order completely; rank 1 and rank 10 count the same |
| nDCG | Ranking quality with graded relevance | Can express “very similar” versus “somewhat similar”; but needs graded ground truth, which is costly |
| mAP | Precision averaged across positions | With binary relevance it captures both how many you hit and how high they ranked — the book's choice |
All three tables point at one sentence: every choice in this problem buys accuracy with cost, latency or rigidity. What an interview actually tests is whether you can justify one choice given a library size, a latency budget and a memory budget.
The skeleton — encode into vectors, retrieve with ANN, re-rank — stopped belonging to image search long ago. Semantic search, the retrieval stage of a recommender, the retrieval layer of RAG, dedup and fraud matching: all the same skeleton with a different encoder bolted on. Learning this chapter gets you the general template for modern retrieval.
① The core transformation: search-by-image is not “judge whether two images are alike” but encode every image into a vector so that visual similarity equals vector proximity — and that reframing takes a query from a billion inferences to one inference plus one lookup.
② The model is representation learning trained contrastively: query, positive and n negatives through one shared-weight encoder, dot-product similarity, softmax, cross-entropy pulling the positive in and pushing negatives out.
③ Three sources of positives: human annotation (accurate, expensive), augmentation (teaches only near-duplicates), and user interaction — the book's workhorse, paid for in noise and exposure bias.
④ The architecture is two pipelines: offline indexing encodes the whole library, online prediction encodes one query image. They couple through the shared encoder, so a model swap means recomputing everything.
⑤ Exact search at O(N×D) is out at billion scale; ANN comes in four families — trees, LSH, clustering/quantisation, and graphs (HNSW) — with Faiss, ScaNN and Annoy as the reference libraries.
⑥ ANN metrics are always a triple: recall, latency/QPS, memory. Any one alone can be gamed. Google Cloud's published reference point is 95–98% recall at p90 < 10ms.
⑦ Offline, pick mAP: MRR wastes information, recall@k has an unknowable denominator, precision@k ignores order, nDCG needs graded labels. Online, watch click-through rate and time spent.
⑧ The re-ranking layer is not optional: dedup, policy and privacy filtering, block lists — vector distance stops none of them.