0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilor
dفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy
jmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈
qtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0
x▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بd
◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgj
∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknq
فehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux
ilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇
psvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞
wz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0اف
◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفi
π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmp
cلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtw
hknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆
orux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π
vy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xc
░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افeh
∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilo
بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsv
gjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░
nqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑
ux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1ب
▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلgjmpsvy▒◇∆π1بdفilorux▓◆∇∑0افehknqtwz░◈Ξ∞xcلg
rehan@neural-mesh :~
$
R
Rehan Rao
all insights
Search Systems 2025 · 05 11 min

Serving 49M records at sub-100ms.

Query parsing, normalization pipelines, and rank shaping. The full anatomy of a large-scale search backend engineered from scratch.

Rehan Rao
AI & Backend Systems Engineer
architecturesearch.pipeline
IngestNormalizeTokenizeIndex ShardQuery ParserRankServe49M ROWS · SUB-100ms P95async batching · shard fan-out · rank cache

49 million rows is not big data. It is the awkward middle — too large to scan, too small to justify a distributed search cluster from day one. The right answer is a boring pipeline with sharp edges.

The shape of the problem

Users type messy strings. The corpus is semi-structured. P95 latency budget is 100ms including network. That budget forces every stage to be measured in single-digit milliseconds.

The pipeline

Every query flows through the same seven stages. The magic is that each stage is pure and independently cacheable.

Index layout

  • Postgres + trigram GIN for fuzzy prefix.
  • Meilisearch shard per vertical for typo tolerance and rank features.
  • Materialized tsvector column, refreshed by change-data-capture.

Rank shaping

BM25 alone ranks nothing users care about. Blend it with recency, popularity, and a learned per-vertical bias. Keep weights in config, not code, so you can A/B-test rank without a deploy.

score = 0.55 * bm25
      + 0.20 * log1p(popularity)
      + 0.15 * recency_decay(created_at)
      + 0.10 * vertical_bias[v]

Serving budget

  • Parse + normalize: < 3ms.
  • Shard fan-out: < 30ms P95.
  • Rank + hydrate: < 40ms P95.
  • Serialize + wire: < 10ms.
note
Warm the top 1% of queries in a rank cache. On any real traffic distribution this covers 40–60% of hits and drops the tail dramatically.