How it is built
Architecture overview
A visual search system answers a question asked with a picture: "what is this shoe, where can I buy it, what plant is that, what does this sign say". The user points a camera at something or circles a region of the screen. The system finds the objects in the picture, turns the chosen one into a vector with an embedding network, retrieves the nearest items from an index of products, places, images or entities, ranks the candidates with more expensive models, and shows them, often together with a text answer written by a multimodal model. Text inside the image is read separately and feeds the same query. Part of this runs on the phone (capture, region choice, sometimes the embedding) and the rest in the data centre, where the index holds up to billions of items.
The design splits retrieval from ranking. Retrieval must be cheap per item and approximate: compare one query vector against a billion stored vectors in a few tens of milliseconds. Ranking can afford a heavy model, but only for a few hundred candidates. Published systems follow this shape: Bing describes a cascaded learning-to-rank framework over deep visual features, serving an index of tens of billions of images with responses in under 200 ms (Bing, 2018); Pinterest, eBay and Alibaba have published comparable systems.
Parts:
- Capture and region choice — resize, detect or segment what the user means — Object detection and image-segmentation (no page yet), with Image resampling filters
- Embedding model — image to a vector where similar things are close — Contrastive learning, vision-transformer (no page yet) on Transformer block, with matryoshka-embeddings (no page yet) and Weight quantization
- Text reading — find and recognise text in the image — Optical character recognition (text recognition)
- Vector index — approximate nearest neighbours under a memory budget, with attribute filters — HNSW, IVF-PQ, Nearest-neighbour search with filters, Perceptual hashing
- Distributed retrieval — fans a query out over shards and merges — Scatter-gather query
- Ranking — reorders the candidates with richer features — Learning to rank, Cross-encoder reranking
- Entity and text side — maps recognised text and labels to knowledge-base entries and rewrites queries — Entity linking, query-expansion (no page yet)
camera / screenshot
│ resize, crop
▼
object detector / segmenter ──► region(s) ──► embedding net ──► query vector (full or short prefix)
│ │
└──► OCR (text lines) ──► query text ▼
│ scatter ─► shard 1: ANN (graph or IVF-PQ) + filter ─┐
▼ ├─► shard 2: ... ├─► gather: merge top-k
entity linking, query expansion └─► shard N: ... ┘
│ few hundred candidates
▼
learning-to-rank (features) ─► cross-encoder rerank ─► results / answer
There are two products of one design: the query path (latency matters, one request at a time) and the index build path (throughput matters, every new item is detected, embedded and inserted). They must use the same embedding model, or vectors are not comparable.
How the parts fit together
Capture and region choice
A photo has several things in it, and the user means one. The pipeline first finds candidate regions. Object detection turns an image into scored, classified boxes in one pass; its network is built from Convolutional networks, post-processed with Non-maximum suppression so one object yields one box, and trained with Data augmentation (crops, colour jitter, flips) so that phone photos in poor light still work. For "circle to search" the region comes from the user's gesture; to refine it into an object outline the system uses image-segmentation (no page yet), now commonly a promptable model in which a click or a stroke is the prompt (the Segment Anything model of Kirillov et al. 2023 is the reference), whose image encoder is a vision-transformer (no page yet).
Before the network sees the crop, the image is resized to the model's input size. Image resampling filters matters here: shrinking by a large factor without a proper low-pass kernel aliases fine texture and changes the embedding, and the same filter must be used at index time and query time. Using the bilinear filter in training and a different one in serving is a classic silent accuracy loss.
For a catalogue index, the same detector runs offline on each listing image, so a "red dress" photo of a model in a room is indexed by the dress crop rather than the whole scene.
Embedding model
The embedding network maps a crop to a vector, typically a few hundred dimensions, so that two photos of the same product (different light, angle, background) are close and unrelated items are far. It is trained with Contrastive learning: two views of the same item are a positive pair, other items in the batch are negatives. The loss pulls positives together and pushes negatives apart; the Embeddings produced are normalised so cosine similarity is a dot product. Hard negatives (similar-looking but different products) keep the model from learning only categories. Where labelled pairs are scarce, they come from user behaviour (clicks, saves) or from augmentations of one image, and CLIP (Radford et al. 2021) shows that image-text pairs can train an image encoder and a text encoder into one shared space, which lets a text query and an image query hit the same index.
The backbone is either a convolutional network or a vision-transformer (no page yet): patch embeddings, position encodings and the encoder blocks of Transformer block. Transformers dominate large-scale training; small convolutional nets still win on phones.
Index size and memory drive the embedding design. matryoshka-embeddings (no page yet) train the vector so that its first 64, 128, 256 ... dimensions are each a usable embedding (Kusupati et al. 2022); the first stage can search with a short prefix and the second stage rescore with the full vector, trading nothing at serving time for a smaller, faster first pass. Weight quantization shrinks the network itself, 8-bit or 4-bit weights with per-group scales, so the model fits and runs on the phone's accelerator; on-device embedding also means the image never leaves the phone if only the vector is sent.
Text reading
Much of what people photograph is text: menus, signs, packaging, documents. Optical character recognition (text recognition) finds text lines in the image and reads each crop with a CTC or attention model; Connectionist temporal classification (CTC) loss lets the recogniser train without labelling which pixel column belongs to which character, and Document image preprocessing (deskew, perspective correction, even lighting) lifts accuracy on phone photos. A lexicon and confidence scores correct and filter the output. The text becomes extra query terms and a filter ("the brand name printed on the bottle"), and translation, if offered, takes the recognised lines.
Vector index
The index stores one vector per item and answers "the k nearest to this query". Exact search compares against everything: a billion 512-dimension float32 vectors is about 2 TB (512 × 4 bytes × 10⁹) and a scan per query. Two families of approximate index cut this:
- Graph index: HNSW keeps a layered proximity graph and finds neighbours with a greedy walk from a sparse top layer; recall is high at low latency, but the graph and the full vectors must sit in RAM, and updates are inexpensive.
- Compressed inverted index: IVF-PQ clusters the vectors with k-means into lists, probes the few closest lists, and stores each vector as a short product-quantization code. At 64 bytes per code, a billion vectors take about 64 GB (64 × 10⁹), small enough for a few machines, at some loss of recall that a rescore with the exact vectors recovers. Faiss, whose GPU design is described by Johnson et al. (2017), is the reference implementation.
Which one to use depends on size and churn: graphs for tens of millions of vectors per shard with tight latency; IVF-PQ for the larger shards where memory dominates.
Real queries carry constraints: category, price, in stock, region, age-appropriate. Nearest-neighbour search with filters combines the neighbour search with attribute predicates, either by checking a filter bitmap while walking the graph, or by applying a bitmap over the candidate lists; compressed bitmaps keep the allow-list small. A filter that is too selective makes the graph walk wander, so the engine switches to a brute-force scan over the few matching items when the match set is small.
Perceptual hashing sits beside the vector index for a different job: compact fingerprints that stay close under resizing and recompression catch exact and near-duplicate copies cheaply, which is used to drop duplicates from results and to flag reposts of the same image before the heavy path.
Distributed retrieval
One machine cannot hold the index. The vectors are split into shards, and Scatter-gather query sends the query to all (or the relevant subset of) shards, each of which returns its local top k, and a coordinator merges them with Top-k selection. The cost is the slowest shard: end-to-end latency is the maximum over shards plus the merge, so tail latency grows with the number of shards. The remedies are the standard ones: sending a duplicate request to a replica after a short delay, per-shard timeouts with partial results marked as such, and giving the whole request a deadline that every stage respects. Sharding by category lets the coordinator skip shards when the query implies one.
Ranking
Nearest neighbours in embedding space are candidates, not answers. The candidate set (hundreds) is re-scored by Learning to rank: a model trained on query-grouped data with a ranking loss, using features that retrieval did not have, such as visual similarity at several scales, text match with the OCR output, price, availability, popularity, seller quality and the user's context. Gradient-boosted trees are the usual workhorse here because they handle mixed numeric features and are fast; quality is measured with NDCG on held-out sessions (Evaluation metrics), not with accuracy.
For the top few dozen, a Cross-encoder reranking model looks at the query crop and the candidate together instead of comparing two precomputed vectors; it is much more accurate and much more expensive, which is why it only touches the final handful. This three-step ladder (cheap vector, feature ranking, joint model) matches the cascade Bing describes.
Entity and text side
Not every answer is a product. A photo of a landmark, a plant, a logo or a recognised name must resolve to a knowledge-base entity. Entity linking maps a mention (an OCR string, a classifier label) to an entity id, or to "none", by generating candidates from an inverted index and scoring them with context; the surrounding NER step finds the mention spans. query-expansion (no page yet) rewrites a short, ambiguous text query with synonyms or generated variants when the text and the image are combined: "red" plus a picture of a bag.
For open questions ("what is this, how do I fix it") a multimodal model receives the crop, the OCR text and the top retrieved items as grounding, which keeps its answer tied to real items.
Data and control flow
One query:
- The phone captures the image or the screen region and resizes it; a detector or the user's gesture selects a region.
- The region is embedded (on device or on a server); in parallel OCR reads text.
- The coordinator sends the query vector and filters to the shards (scatter).
- Each shard runs its ANN search, applies filters, returns its top k.
- The coordinator merges, drops duplicates, runs the feature ranker, then the cross-encoder on the top part.
- Entities are linked, the answer model is called if needed, and the result list is rendered.
One item added to the index:
- A new listing image arrives; the detector crops objects.
- Each crop is embedded with the current model version and compressed to a code.
- The code, id and attributes go into the right shard; the graph or list is updated.
- When the embedding model changes, the whole index is rebuilt under a new version and switched atomically, because old and new vectors cannot be compared.
Scaling
- Memory bites first: vectors dominate. Levers: shorter prefix dimensions, PQ codes, 8-bit or binary quantization with rescoring, disk-resident exact vectors for the final rescore.
- Tail latency grows with shard count. Levers: fewer larger shards where memory allows, replicas and backup requests, deadlines, category routing.
- Embedding throughput at index build: billions of crops through a network. Levers: batch on GPUs, smaller backbones for the long tail, embed only on change.
- Update rate: a marketplace changes constantly. Lever: a small mutable shard for fresh items searched beside the large immutable ones, merged in the background.
- Ranking cost grows with candidates times model size. Levers: strict budgets per stage, distilling the cross-encoder into the feature ranker.
Failure modes
| Failure | Symptom | Cause | Fix |
|---|---|---|---|
| Wrong object | results for the background, not the item | detector picks the largest region, not the intended one | show the box and let the user adjust, use the gesture as a prompt |
| Domain gap | works on catalogue photos, fails on phone snaps | training images are clean studio shots | augment with phone-like noise and crops, train on click pairs |
| Version mismatch | nonsense neighbours after a model update | query embedded with a new model against an old index | version tag on vectors, rebuild and switch atomically |
| Resize mismatch | silent recall drop | different resampling filter at index and query | one preprocessing spec, golden-file test |
| Low recall under filters | nothing returned for a narrow filter | graph walk blocked by the filter | pre-filter to a scan when selectivity is high |
| Duplicate-heavy results | ten copies of one image | no duplicate suppression | perceptual hash grouping before ranking |
| Slow shard | p99 latency spikes | one overloaded replica | hedged requests, partial results, rebalance |
| OCR misread | brand typed wrong, wrong entity | blur, glare, unusual fonts | confidence threshold, spell correction against a lexicon, show candidates |
| Rank drift | clicks fall after a retrain | ranker trained on logs biased by old ranking | randomised exploration slice, counterfactual evaluation |
| Sensitive content | people or private documents retrieved | no policy on faces and documents | filters at index time and query time, on-device processing where possible |
Real implementations
| name | what it is | repo | licence | notes |
|---|---|---|---|---|
| Google Lens, Circle to Search | camera and screen-region search | proprietary | proprietary | the reference product |
| Apple Visual Look Up | on-device recognition in Photos and Camera | proprietary | proprietary | partly on device |
| Pinterest Lens, Bing Visual Search | published production systems | proprietary | proprietary | see Sources |
| Faiss | vector similarity search: flat, IVF, PQ, HNSW, GPU | facebookresearch/faiss | MIT | index layer |
| hnswlib | header-only C++ HNSW with Python bindings | nmslib/hnswlib | Apache-2.0 | graph index |
| Milvus | distributed vector database with filtering | milvus-io/milvus | Apache-2.0 | sharding and filters |
| OpenCLIP | open image-text embedding models and training code | mlfoundations/open_clip | see repo | embedding model |
Sources
- Web-Scale Responsive Visual Search at Bing, 2018: tens of billions of images, under 200 ms, cascaded learning to rank. paper
- Y. Jing et al., Visual Search at Pinterest, 2015. paper
- Visual Search at eBay, 2017. paper
- Visual Search at Alibaba, 2021. paper
- J. Johnson, M. Douze, H. Jégou, Billion-scale similarity search with GPUs, 2017. paper
- Y. Malkov, D. Yashunin, Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs, 2016. paper
- A. Radford et al., Learning Transferable Visual Models From Natural Language Supervision (CLIP), 2021. paper
- A. Kirillov et al., Segment Anything, 2023. paper
- A. Kusupati et al., Matryoshka Representation Learning, 2022. paper