Matching people by meaning does not say who you may advertise to

Insights, Updates18 Aug 2026Damian Naglak
260818 damian

A sportsbook asks for the people most likely to bet on football. The closest match anywhere in the data lives in a state where the company holds no licence. The model was right and the answer is worthless.

The last two posts were about finding the closest people among billions. Nobody wrote down who belongs in the audience and no score makes somebody a member, so everybody scores something against the description. Comparing against everybody is too slow, so each person is stored next to a short list of their nearest neighbours, and the search hops from person to person, always towards somebody closer. A few hundred stops instead of a billion comparisons. What comes back is a ranking, and it says nothing about who you may advertise to.

A profile often says where someone lives, so the vector half knows. Pooling flattens a whole browsing history into one vector, so two words about a city sit among hundreds of others, and one state reads much like the next. The vector leans one way, it never certifies. And the conditions that disqualify a person were never in their browsing history at all. Whether the sportsbook holds a licence in that state sits in the company’s records, and changes when a legislature votes. Whether they agreed to be advertised to sits in a consent record. Whether you can reach them depends on an ID you may bid on. Anyone who already opened an account is on the advertiser’s exclusion list. A better model ranks people better and learns none of this.

The obvious way to combine them is to take the closest hundred and drop the ones you cannot use, which in a narrow market leaves nobody. So the licence check runs during the hopping instead. Every time the search reaches somebody it asks two things: are they close, and are they allowed. Only the allowed ones go on the shortlist, and the rest still get hopped over, because their neighbour lists are the route to everybody behind them. The search stops when nobody left to visit is closer than the worst person on the shortlist, so when few qualify it fills slowly and the search keeps running. If one person in twenty is allowed, the search stops at twenty of them for every usable name it collects. Removing a few people costs almost nothing. Requiring something rare is what stretches the search.

The way out is to split people in advance by a separate index per state, so everybody inside it is eligible. Licences, caps, budgets and exclusions change by the second, so those get checked as the search runs. When very few qualify, the better move is to stop hopping and compare against the eligible ones directly, which is what engines do below a size threshold. And the top of the ranking wears away as a campaign runs: the best matches get served first, so they cap out first, and the ones who sign up move to the exclusion list.

Search over vectors is quick because it never looks at most of the people. Every rule about who you may advertise to is a reason to look anyway.