Why vector search misses SKUs and internal product codes

Big text SKUs Break Search next to an isometric white sieve where blobs pass through and tag chips fall out.

Vector search misses SKUs and internal product codes because the embedding model has never seen them, so similarity scoring has nothing to grab for a string like ZRX-2025. It gets ranked against real products almost at random, and swapping embedding providers changes the decimals but not the outcome. What vector search does well on a store is genuinely useful: it bridges hoodie to sweatshirt, forgives typos, and matches a query in one language against product copy in another. Angela Shi ran four embedding models, from 2014 GloVe averaging up to text-embedding-3-large, through both halves of that story in a long Towards Data Science piece on RAG retrieval failure modes, and the failure half is the one store owners feel.

My position for WooCommerce search: keyword search stays the retriever of record. Embeddings earn a slot as a fuzzy fallback and as a discovery tool for the store’s own vocabulary, and that is as far as I would take them. This is close to what the article argues for enterprise corpora, and it maps well onto WordPress because the two things it asks for, an exact-match index and an expert keyword dictionary, already exist here in different shapes.

Why the store’s vocabulary breaks vector search

The article’s simplest test is the word “pool”. In a reinsurance contract that is a risk-sharing instrument; in general English it is a body of water. On three of the four models, a reinsurance paraphrase ranked below a random sentence about a train departure, and ada-002, the model behind a lot of production RAG, put the timetable ahead by 0.010. The swimming sense is all over the public web and the risk sense is buried in actuarial text the model barely saw at training time.

A product catalog is that case at full strength. SKU-ZRX-2025, a tier name like Pro Elite, the abbreviation your supplier prints on packing slips: none of it is in the training distribution, while the wins everyone demos in week one come from public vocabulary baked into the weights. A larger model widens margins on public terms, and the article shows one compound, “hot dog”, where only text-embedding-3-large picked the right sense at all, but for strict unknown identifiers there is no sense to recover. The ranking is noise, and a reranker stacked on top just reorders noise.

Term similarity is not answer relevance

Even when the words are in the model, embeddings rank by topic rather than question-to-answer fit. In the article’s cleanest test, for the query “capital of France”, the candidate “Paris is the capital of France” never wins. The winner is “Capital of Italy”, because it repeats the literal phrase from the query. Moving from a 300-dimension 2014 model to a 3072-dimension 2024 model did not flip that once.

Negation is the same mechanism pointing the other way. For “what is NOT a city”, the correct answer, “Table”, ranked last on every model, because the query carries the word city and anything city-adjacent scores higher. Real users write negations exactly when the system has already failed once: the customer asks for the premium amount, gets the deductible, and corrects with the premium, not the deductible. That correction adds deductible to the query and pulls deductible results closer, so the retry is worse than the original. On a store this looks like jacket without fur trim ranking fur-trim jackets.

WordPress keyword search does not handle exclusion either, but it gives you real tools for it: post__not_in, a meta_query with != or NOT EXISTS, and the pre_get_posts hook to set them once you have parsed the exclusion out of the query. The fix is parsing into a filter, because no scoring function represents a logical not.

Route exact identifiers before anything fuzzy runs

The article closes on a case study worth repeating with its numbers. A team over commercial insurance contracts spent three months fine-tuning embeddings and moved recall from 71% to 76%. Breaking their 200 questions down by type showed 92% on conceptual questions, 23% on negation, 31% on exact references, and 18% on internal acronyms, so the average hid two buckets near zero. Adding BM25 next to the vector search took two days and lifted exact-reference recall to 88%. A glossary-based query expansion took another day and lifted acronym recall from 18% to 71%. That was one week of structural work against three months of model tuning.

In WordPress the exact-match index already exists: postmeta. If the query looks like a SKU or a product code, match it exactly and skip the scoring path entirely.

add_action( 'pre_get_posts', 'bbioon_route_exact_sku' );
function bbioon_route_exact_sku( WP_Query $query ) {
	global $wpdb;

	if ( is_admin() || ! $query->is_main_query() || ! $query->is_search() ) {
		return;
	}

	$term = sanitize_text_field( $query->get( 's' ) );
	if ( '' === $term ) {
		return;
	}

	$ids = $wpdb->get_col(
		$wpdb->prepare(
			"SELECT post_id FROM {$wpdb->postmeta}
			 WHERE meta_key = '_sku' AND meta_value = %s",
			$term
		)
	);

	if ( empty( $ids ) ) {
		return; // not a SKU, let the normal search path run
	}

	$query->set( 's', '' );
	$query->set( 'post__in', $ids );
	$query->set( 'posts_per_page', count( $ids ) );
}

Two notes. Map matched variation IDs to their parents before you set post__in (variable products keep per-variation SKUs on product_variation rows, and the shop archive query will drop them otherwise). And this runs before the main query is built, so the exact identifier never enters the similarity lane and there is no score to get wrong.

If you want this kind of routing on your store, deciding what goes to an exact match, what goes to MySQL full text, and what needs a vector, that is work I do regularly, and it usually starts with labeling a sample of your real search queries before anyone picks a model.

The keyword dictionary is already a WordPress object

The article’s production answer is a curated alias dictionary: seed it with terms the expert already knows, run a line-level embedding search to surface corpus phrasings nobody anticipated, have the expert keep the real aliases, then run retrieval against the dictionary so every match is auditable. It also takes apart HyDE, the trick of generating a hypothetical answer and embedding that, by showing the load-bearing part is the keywords the rewrite happens to contain. Asking the model for those keywords directly, or getting them from the person who knows the catalog, retrieves the same passages with less infrastructure. The original HyDE paper is worth reading if you want the technique from its source.

WordPress gives you the containers. Product tags and global attributes are alias dictionaries with an admin UI that merchandisers already maintain. For aliases you do not want exposed as taxonomy, a small options array or one table is enough, and store owners tend to be faster than a model at listing the three names customers use for one product. I wrote about where to stop when adding semantic search to WooCommerce, and the exact-ID side of this same problem is covered in an earlier post on why vector similarity misses exact IDs.

Score by query type, not one recall number

Two signals the article gives for over-investment in embeddings: fine-tuning is on the roadmap before anyone has broken the failure cases down, and retrieval is reported as a single number. The single number is the one you control cheapest. Take a hundred real queries from your store’s search log, label each as conceptual, exact identifier, negation, or internal term, and measure hits per bucket.

Log the rank position of the correct product too, not just whether it was first. In the article’s page-scale test one question only worked because the right page sat at rank two while rank one was wrong, which means top-1 evaluation would call it a failure and top-3 evaluation would call it fine. Both readings are wrong until you know the result depth your theme shows.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.

Leave a Comment