Why public tenders are hard to find: the measurement
This is the methodology behind Why public tenders are hard to find: how the numbers were produced, the three measures defined once, and the honest limitations. Every figure in the study is available as a downloadable data file — tender-search-results.json.
The question
When a supplier cannot find a tender that is genuinely relevant to them, why not? The answer here is neither “buyers write nothing” nor “the search is weak”. It is a language gap: the words buyers use and the words searchers type are often different words for the same contract. Most of that gap can be closed by widening the search, but widening carelessly adds noise, so it has to be done with specific terms and tested.
Data
- Corpus: 2,405 open UK Find-a-Tender notices (snapshot 4 August 2026), each with a deadline still in the future.
- Searches: 20 real customer searches.
- Relevance: a language-model judge, checked against 222 human labels (quadratic-weighted kappa 0.75), graded every notice 0 to 3 per search. Relevant means grade 2 or 3, giving 836 relevant pairs (290 squarely relevant, 546 related).
Searchable text
Title and description only. The CPV classification code is left out on purpose: it is patchy, and its labels reuse broad words like “services” so widely that matching on it creates connections that are not really there. BM25 is implemented inline (no external library) so the whole test can be reproduced.
Three measures, defined once
- Match: one of the search words appears somewhere in the notice’s title or description.
- Recall: the share of known-relevant tenders that the search returns in its top results (top 200 unless stated).
- Precision: the share of the top returned results that are actually relevant.
A tender can only be returned if a word matched, so recall is never higher than the match. The comparison figures below are averaged across the searches.
Result 1: how often the searcher's words are missing
Across all 836 relevant pairs, the share where none of the search words appears in the notice:
| Search words missing | |
|---|---|
| All relevant tenders | 36% |
| Squarely relevant (the ones you wanted) | 19% |
| Related, nearby contracts | 45% |
It is a language gap, not empty notices. A “Workforce Skills Framework” that would run apprenticeships describes itself one level up and never says “apprenticeship”.
Result 2: widening the search closes most of the gap, and stays clean
On the 9 list-style searches, comparing the first phrase alone against the full list of related terms, over the same topic and the same relevant tenders:
| Match | Recall (top 200) | Precision (top 20) | |
|---|---|---|---|
| First phrase only | 27% | 26% | 37% |
| Full list of related words | 83% | 52% | 48% |
The full list roughly doubles recall. It does not add noise: precision rose from 37% to 48%, because the tenders matching several specific terms rose to the top. For the squarely-relevant tenders, the full list matched 92% of them and returned 65%.
Important condition: this gain comes from adding specific related terms. Broadening a search by using one loose word does the reverse. Searching “vehicle” on its own, rather than “vehicle hire” or “car hire”, catches the relevant notice but also catches “contracting vehicle”, “investment vehicle”, and every other kind of vehicle in the corpus.
Building the word list
A searcher used to have to imagine every related word themselves, and any word left off silently drops every tender that used only that word. A language model can now generate a first draft in seconds, so the barrier is much lower. But the list still has to be checked, because a model will include broad or ambiguous terms that add noise, and the resulting search has to be tested.
Result 3: what a full list still cannot reach
Even with the full list, a stubborn minority of relevant tenders still does not match. Most are related contracts described in words no reasonable searcher would have listed; a smaller number are notices too thin to carry matchable words. The notices that stay missing are shorter than the ones found (median about 600 characters, compared with about 930).
Result 4: notice format
Frameworks and Dynamic Purchasing Systems lose the search words 42% of the time, compared with 29% for one-off contracts. This is not because they are sparser. Their descriptions are slightly longer on average (median 848 characters, compared with 775 for one-off notices), and one-off notices are far more likely to be almost empty (17% under 250 characters, compared with 4% for frameworks and DPSs). The words go missing because a standing-list notice spends its text on how to join and which broad categories it covers, and mentions the specific thing being bought only briefly, if at all.
For context: keyword recall on the raw searches
BM25 over title and description, using the queries exactly as customers typed them (a mix of single-phrase and list-style), recall averaged over all 20 searches: 30% in the first 50 results, 44% in the first 200. This is not a fixed ceiling; it moves with how widely the search is worded, as Result 2 shows.
Honest limitations
- One corpus (open UK Find-a-Tender), 20 searches: a case study, not a universal law.
- The word test matches words, not meanings, so it cannot see genuine synonyms and slightly overstates how often a word is missing. The true gap is a little smaller than 36%, and generating the related words well recovers more than this test shows. This works against the headline, not for it.
- Recall depends on results depth; both the top 50 and the top 200 are reported so the number is not cherry-picked.
The data
Every number above is available as a single machine-readable file: tender-search-results.json. It contains the word-absence rates, the widening (stacking) curves, the read-depth curves, and the notice-format breakdown.
Back to the article: Why public tenders are hard to find.