Learning pathsA
GUIDED PRACTICE

FB Post Search

Design search across posts while respecting audience visibility, deletion, and recent edits.

Interview scope and guarantees

Search authorized posts by text, filter by author or time, rank results, and paginate. Agree index freshness and deletion propagation targets. Search relevance may be approximate, but access control must not be bypassed by a stale index.

Capacity worksheet

Assume 100 million posts/day averaging 1 KB of searchable text: 100 GB/day raw. If analyzed index data is 2× raw and replicated twice, budget around 400 GB/day before retention and merges. At 10,000 queries/s with 20 shard requests each, the cluster sees 200,000 shard-level searches/s.

Concrete API contract

Contract / pseudocode
GET /search?q=...&author=...&cursor=...
POST /posts {text,visibility}
DELETE /posts/{id}
Search response includes post IDs, snippets, cursor and index freshness.

Data model and access paths

Contract / pseudocode
posts(post_id PK,author_id,text,visibility,version,deleted_at)
index_document(post_id,terms,author_id,created_at,visibility_version)
index_checkpoint(partition,offset)
search_cursor(query_hash,pit_id,sort_values,expires_at)

Evolve a solution and explain each change

Three architecture decisions for FB Post Search, including the pressure each introduces.
Scroll to inspect the diagram, or open it at full size.

Figure — Three architecture decisions for FB Post Search, including the pressure each introduces.

Step 1: Search source records

Filter authorized posts and match terms directly for a small workload. Scanning the source database is slow at scale.

Step 2: Build a search projection

Index post text asynchronously through versioned change events. The index can lag or retain deleted/private content.

Step 3: Revalidate and rebuild

Filter candidates against current permissions and support versioned projection rebuilds. Search relevance and index freshness are separate quality dimensions.

Responsibility overview

Connected responsibilities for FB Post Search. Trace the authoritative and derived paths separately.
Scroll to inspect the diagram, or open it at full size.

Figure — Connected responsibilities for FB Post Search. Trace the authoritative and derived paths separately.

Worked end-to-end scenario

Post p9 is indexed at version 3. The author edits it to version 4, then deletes it at version 5. Workers receive those changes out of order. The index must reject the old version 3 update after applying the version 5 tombstone. A search query returns candidate IDs from the index; the serving layer checks current visibility before returning protected text. Permission filtering only after displaying a snippet is already too late. To rebuild, populate a new index from a consistent snapshot plus changes, validate it, and switch an alias without mixing cursor state across incompatible ranking snapshots.

Why these access paths matter

The source post table is authoritative; the search index stores document ID, content version, terms, and permitted filtering metadata. Use stable tie-breakers and search-after style pagination tied to a search snapshot when needed. An authorization index may reduce candidate volume, but its stale state cannot be the only control for strict privacy.

Build the baseline first

FB Post Search: baseline request paths.
Scroll to inspect the diagram, or open it at full size.
  1. Post transaction → outbox → indexer.
  2. Query → inverted index → ranked candidates.
  3. Current authorization → hydrated results.

Evolve the design under load

FB Post Search: additional scaling and recovery paths.
Scroll to inspect the diagram, or open it at full size.
  1. Index shards → scatter/gather → bounded top results.
  2. Replica groups → query capacity isolation.
  3. New index generation → backfill and catch-up → alias switch.

Defend the hardest decision

An inverted index maps terms to posting lists; analyzers determine tokenization and normalization. Matching candidates is not the same as ranking them. Apply coarse searchable ACL filters early, then check current access before returning text or snippets. For stable pagination, use a point-in-time snapshot and search-after values with a deterministic tie-breaker rather than large offsets.

Failure and recovery analysis

A deletion event arrives before an older update due to retries. Index updates must compare document versions so stale writes cannot resurrect content. If search indexing lags, show reduced freshness while preserving primary writes. Reindex into a new generation, replay changes from the snapshot boundary, and switch atomically after validation.

Security and privacy boundary

Authorize before returning snippets, protect private terms in logs, and rate-limit exhaustive search scraping.

Interview follow-ups with reasoning

Question: How do multilingual analyzers affect schema?

Show answer and explanation

Answer: Store language-specific fields or choose analyzers deliberately.

Question: How do you reduce shard fanout?

Show answer and explanation

Answer: Route constrained queries by author or tenant where possible.

Question: How do you test privacy?

Show answer and explanation

Answer: Revoke access while replaying old events and assert no snippets leak.

Operate and verify the design

Index freshness, query fanout, deleted-document resurrection and authorization filter failures.

Replay an old update after a deletion and verify that neither the result nor snippet reappears.

A second scenario to test transfer

A post changes from public to a private group. The search index still contains its old public token document for 30 seconds. Search may retrieve that ID, but the authorization step rejects it and suppresses the snippet. Asynchronous index cleanup then removes it from future candidate sets. Measure both exposure correctness and cleanup lag.

How can search remain available during eventual index cleanup without showing a newly private post?

Show answer and explanation

Answer: Allow the index to return a candidate ID but consult current authoritative visibility before returning the post or any excerpt. Versioned delete propagation reduces future index matches; access control on the response is the safety boundary. The query cache also needs viewer scope or an authorization-safe representation.

Compare alternatives

LayerPurposePrivacy control
Text indexCandidate retrievalScope fields and limited payload
Authorization ownerCurrent viewer accessCheck before snippets
Deletion tombstonePrevent resurrectionVersioned writes
Result cacheReuse query workViewer/audience-aware key

A design-changing exercise

A private post is removed from the database but remains searchable for a minute. Can a disclaimer solve it?

Show answer and explanation

Answer: Not for a strict privacy contract. Current authorization must protect content and snippets while deletion propagates to the projection.

Design workshop: retrieve candidates, then authorize

Core scope is text search over visible posts with edits/deletion and stable pages. Semantic embeddings are an extension. Choose indexed freshness within ten seconds, p95 under 300 ms for admitted bounded queries and authoritative authorization before returning content or snippets.

Index mapping includes postId, authorId, body tokens, audience hints, sourceVersion and deleted. Tokenization lowercases and normalizes under a pinned analyzer. For documents D1='red bicycle', D2='blue bicycle' and D3='red boat', postings are red→{D1,D3}, bicycle→{D1,D2}. AND intersection returns D1; OR returns all three and needs scoring. BM25-style scoring combines inverse document frequency, term frequency saturation and length normalization; show the ranking objective rather than claiming a term match alone gives relevance.

Worked inverted-index retrieval. red / D1,D3 / Authorized candidates only; bicycle / D1,D2 / Apply same analyzer as indexing; red AND bicycle / D1 / Hydrate current visible D1; red OR bicycle / D1,D2,D3 / Score then authorization-safe top-up; D1 made private / Index may still return D1 / Suppress body, snippet and media until ACL permits
Scroll to inspect the diagram, or open it at full size.

Figure — Worked inverted-index retrieval.

Hash post ID to shards for write balance; text queries scatter to selected shards and merge scored candidates. Audience filters prune work but are not the final privacy authority. If many hits are inaccessible, bounded oversampling can fill the page; when its budget is exhausted return fewer results with an honest continuation, not an unbounded loop. Avoid exposing restricted snippets in caches or search-index responses accessible to clients.

Use a point-in-time index snapshot with search_after carrying a deterministic score/tie sort tuple. Sign the PIT ID and tuple to bind query, viewer and expiry. A changed query creates a new cursor; an expired PIT returns reset_required. Current ACL filtering still applies despite the PIT, so visibility can change between pages without exposing protected posts.

Reindex while keeping removals effective. Post DB/outbox to Indexer: Snapshot source at watermark W; Indexer to Old/new indices: Build new mapping/analyzer index from snapshot; Post DB/outbox to Indexer: Replay edits/deletes after W with source versions; Indexer to Old/new indices: Retain durable tombstone documents or version ledger; Indexer to Old/new indices: Catch up to chosen cutover watermark; verify counts; Search API to Old/new indices: Switch alias; authorize every hydrated result
Scroll to inspect the diagram, or open it at full size.

Figure — Reindex while keeping removals effective.

For stale-event protection choose soft tombstone documents carrying the last sourceVersion, or a durable external version ledger checked by the indexer. Elasticsearch's physical delete does not keep version evidence indefinitely; index.gc_deletes bounds that evidence. Align tombstone retention with maximum replay and backfill horizon, including restores. When tombstones are purged, old history must rebuild into a new epoch/index rather than replay into the current one.

Reindex builds a new projection, consumes changes after its snapshot watermark, compares document counts and representative queries, then switches an alias. Do not drop the old index until rollback retention expires. During both paths authorize against current source state. Rate-limit long queries and cap shard/time budgets. Monitor index lag, tombstone age, unauthorized-hit ratio, top-up work and PIT resets independently.

Exercise: Delete version 8 is physically removed, its version evidence expires, and update version 7 arrives from an old replay. What stops resurrection?

Show answer and explanation

Answer: The selected durable tombstone/version ledger rejects 7. A bare physical delete with finite version retention cannot support an indefinite replay guarantee. Alternatively isolate the replay into a new projection and reconstruct correct source state there.

Elasticsearch pagination and delete version retention document the relevant provider boundaries.

Technical references

Elasticsearch search pagination.

PostgreSQL transaction isolation and concurrent updates.

11:00Self-guided practice timer
The timer resets when you leave this page. Save your design separately.
Your challenge

How can search remain available during eventual index cleanup without showing a newly private post?

Your design draft

Clarify assumptions, explain your approach, and test the difficult cases. Save your draft, then compare it with the study notes.

Read study notes

Self-review checklist

Self-guided practice. Automated AI feedback and code execution are not connected.