Skip to content

Speed up search by ranking from a title map - #3408

Draft
enf0rc3 wants to merge 1 commit into
mainfrom
willlaugesen/search-title-map
Draft

Speed up search by ranking from a title map#3408
enf0rc3 wants to merge 1 commit into
mainfrom
willlaugesen/search-title-map

Conversation

@enf0rc3

@enf0rc3 enf0rc3 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Search ranking needed a URL and a title for every result it ordered, and Pagefind keeps both inside the per-page fragment. So ordering thirty results meant downloading thirty files before the panel could draw a single row — which is what a reviewer noticed on the last PR, watching them trickle through six at a time on Slow 4G.

The build now writes a small map of result id to URL and title beside the index. Pagefind's own result stub already carries the id of its fragment, so that map is all ranking needs.

What this gives

  • A third of the downloads per search. 10 fragments for a settled query, down from 30 to 35.
  • Faster first results. On Slow 4G, 7.2 s against 8.9 s — and that run served the map uncompressed at 122 KB, so behind the CDN, where it is 28.5 KB, the gap is wider.
  • Identical relevance. Unchanged on both traffic-weighted query sets.
  • A page the query names wins from anywhere. Ranking now sees every result, where it used to see the first thirty. The shallow-page shortlist of 227 that rescued those pages is gone with it, along with the second Pagefind query per search and the filter it needed on every page.
  • Graceful failure. A map that goes missing or disagrees with the index falls back to ranking the rows it draws, which is what the engine did before.

How this was measured

Both traffic-weighted query sets replayed through the real overlay against the merged main, same machine, same method:

before after
fragments per settled query 30–35 10
real-searches, weighted S@1 / S@5 57% / 84% 57% / 84%
top-pages, weighted S@1 / S@5 90% / 98% 90% / 98%
Slow 4G, typing "kubernetes" 8.9 s 7.2 s

Relevance holding exactly is the point. Widening the ranking window from thirty rows to the whole result set moved nothing, so the shortlist it replaces was doing its job, and this does the same job for a third of the fetches.

219 Playwright tests pass, including the existing ranking, paging and tab-count cases unchanged.

Worth a reviewer's opinion

The map is fetched eagerly alongside the index, so someone who opens the overlay and never types now pays 28.5 KB they did not before. Moving it to the first keystroke would avoid that, at the cost of putting it on the path of the first search.

Ranking needed a url and a title, and Pagefind keeps both in the per-page
fragment — so ordering thirty results meant fetching thirty files before the
panel could draw, and a page ranked past thirty could not be reached at all. The
build now writes a map of result id to url and title beside the index, which is
the join Pagefind's own result stub already carries.

So the whole result set is ranked before anything is fetched, and fragments are
fetched only for the rows being drawn: ten per batch, against thirty to
thirty-five for every settled query before. On Slow 4G with the map served
uncompressed, first results arrive in 7.2s against 8.9s; the map is 28 KB
gzipped, so most of that 122 KB is transfer a CDN removes.

The shallow-page search this replaces is gone with it — the second Pagefind
query, the landing filter, LANDING_DEPTH and the attribute it needed on every
page's content div. A page the query names now wins from anywhere in the list
rather than from a shortlist of 227.

Relevance holds on both traffic-weighted sets: real-searches 57% w-S@1 and 84%
w-S@5, top-pages 90% and 98%, unchanged either side.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@team-marketing-branch-protections

Copy link
Copy Markdown

Pull request environment is available at https://stoctodocspr3408.z22.web.core.windows.net.

You can view the ephemeral environment status in Octopus Deploy.

This environment will be automatically deprovisioned when the pull request is closed, or after 7 days of inactivity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants