Skip to main content

Every product has a search bar. Almost nobody owns it. It gets built in the first fortnight as a LIKE '%query%' against one column, it survives three years of feature work untouched, and then someone opens an analytics dashboard and discovers that a third of searches return nothing at all. Search is the feature users reach for when they already know what they want, which makes it the single worst place in your product to disappoint them.

In 2026 that problem has a second audience. AI agents now hit your search endpoints too, and they query nothing like humans do. The gap between “we have a search box” and “we have a search architecture” has become commercially expensive.

TL;DR

  • Most application search failures are relevance problems, not infrastructure problems. Adding a bigger search cluster to a bad ranking model just makes the wrong answers arrive faster.
  • PostgreSQL now covers far more of the search ladder than teams assume: native full-text search, BM25 ranking via ParadeDB’s pg_search, and vector similarity via pgvector, all queryable in one SQL statement.
  • Hybrid search (keyword plus vector, fused with Reciprocal Rank Fusion, then reranked) is the default architecture for 2026, because exact terms like SKUs, error codes and surnames are exactly where pure semantic search falls apart.
  • Keep your extensions patched. pgvector 0.8.2, released 26 February 2026, fixed CVE-2026-3172, a buffer overflow in parallel HNSW index builds that could leak data from unrelated tables.
  • AI agents are now a first-class search consumer, and they need structured filters, stable identifiers and explicit relevance signals, not a fuzzy text box.
  • Instrument zero-result rate and click position before you change a single line of ranking code.

The ladder nobody walks deliberately

There is a well-worn progression for application search, and most teams stumble up it under pressure rather than choosing a rung on purpose.

Rung one: LIKE or ILIKE. Fine for an admin table with 500 rows. It cannot rank, cannot handle stemming, cannot match “running shoes” to a product called “shoe, runner’s”, and does a sequential scan on anything with a leading wildcard.

Rung two: PostgreSQL full-text search. A tsvector column, a GIN index, ts_rank for ordering. This is genuinely good, badly underused, and free. It gives you stemming, stop words, phrase queries and language configurations without adding a service to your architecture. For a documentation site, a knowledge base, or a catalogue in the low hundreds of thousands of rows, this is often the correct final answer.

Rung three: BM25 inside Postgres. ParadeDB’s pg_search extension brings a Tantivy-backed BM25 index into the database, alongside faceting, filtering and result highlighting, with Apache DataFusion handling aggregations. It is AGPLv3 for the community edition, which is a licensing conversation worth having before you build on it, not after. The pitch is compelling: one Postgres for application data, full-text search and vector retrieval, so you stop running a synchronisation pipeline between your source of truth and your search index.

Rung four: a dedicated engine. Elasticsearch, OpenSearch or Typesense. You move here for reasons that are operational rather than aspirational: instant-search latency budgets under 50ms, typo tolerance as a product requirement, heavy faceted navigation across tens of millions of documents, or per-tenant index isolation you cannot express cleanly in SQL.

The mistake is jumping from rung one to rung four during an incident. That decision buys you a distributed system, an indexing pipeline, a second source of truth with its own freshness lag, and a new class of “why is this product missing from search” support ticket. It does not, by itself, buy you relevance.

Relevance is the actual problem

Here is the uncomfortable part. When search is bad, the cause is almost never that the index was too slow. It is that the ranking function does not agree with what your users consider a good answer.

Keyword search using BM25 is excellent at precision on rare terms. Search for an error code, a part number or a customer surname and BM25 will find it, because it rewards terms that are rare across the corpus. What it cannot do is understand that “can’t log in” and “authentication failure” are the same problem.

Vector search does the opposite. Embeddings capture meaning, so “can’t log in” retrieves the authentication article happily. But ask a vector index for SKU RH-4482-B and it will return something plausibly similar and completely wrong, because that identifier carries almost no semantic signal. Anyone who has watched a purely semantic search return confidently adjacent nonsense knows the failure mode.

Hybrid search exists because both halves are load-bearing. The standard 2026 shape is: run the keyword query and the vector query in parallel, fuse the two result lists with Reciprocal Rank Fusion (which needs no score normalisation, just ranks), take the top 40 to 50 candidates, then pass them through a cross-encoder reranker to produce the final handful. Retrieval is cheap and recall-oriented; reranking is expensive and precision-oriented. Doing both is how you get the best of each without paying reranker cost across the whole corpus.

The same architecture underpins retrieval-augmented generation. When a RAG system produces a bad answer, the retrieval step is usually the culprit rather than the model. Teams spend weeks tuning prompts against a pipeline that never surfaced the right document in the first place.

The Postgres-first case in 2026

pgvector remains the sensible default for vector similarity, and it is production-ready in a way it simply was not three years ago. Two index choices matter. HNSW gives better recall-to-latency trade-offs and needs no training pass, which is why it has become the default. IVFFlat builds faster and uses less memory, which still wins for smaller, mostly static datasets where build time and RAM are the binding constraints.

One caveat that deserves more attention than it received: pgvector 0.8.2, released on 26 February 2026, patched CVE-2026-3172, a buffer overflow during parallel HNSW index builds that could leak data from other relations or crash the server. Database extensions sit outside most teams’ software composition analysis. They are compiled code running inside your most sensitive process, and they need the same currency SLA you apply to application dependencies. If you cannot name the pgvector version in production right now, that is the finding.

The strategic argument for staying in Postgres is not performance. It is that you avoid a distributed data problem. One transaction writes the row, the search document and the embedding together. There is no consistency window, no reindex backlog, no “the search index is 40 minutes behind” incident at the worst possible moment. For most SME and startup workloads, that operational simplicity is worth more than the last 20% of query performance.

Search has a second user now

The newer consideration is that agents query differently from people. Human search is short, repetitive and long-tailed in predictable ways. Agent search is specific, authenticated, and rarely repeated, which means it caches badly and hits your index cold far more often.

Agents also need different affordances. A text box is a poor interface for a machine. What an agent wants is a search API with structured filters, explicit field selection, stable resource identifiers it can cite, pagination that does not shift under it, and relevance scores it can reason about rather than an opaque ordering. If you are exposing capability through MCP or an equivalent tool interface, your search endpoint is very likely the first thing an agent will reach for, and the quality of that interface directly determines whether the agent gives your users a correct answer or a confident fabrication.

This is worth designing for now rather than retrofitting. Agent-readable search is largely the same work as good API design, just with relevance metadata treated as part of the contract.

What to actually do

  1. Measure before you build. Log every query, its result count and the position of whatever the user clicked. Zero-result rate and click-position distribution will tell you more in a fortnight than any architecture review.
  2. Build a judgement set. Take your 100 most common queries and have a human record the correct answers. This is your regression suite. Without it, every ranking change is a guess, and you will improve one query while quietly breaking nine.
  3. Exhaust Postgres first. Move to a proper tsvector with a GIN index and weighted fields before you consider a search cluster. Most teams find their problem disappears here.
  4. Add vectors only when the queries justify it. If your users search for natural-language problems rather than known nouns, hybrid retrieval earns its complexity. If they search for part numbers, it does not.
  5. Rerank last. A cross-encoder over 40 candidates is the highest-leverage single change in most retrieval pipelines, and it is far cheaper to add than a migration to a new search engine.
  6. Treat the search index as a security surface. Filter by tenant and permission at query time, in the index, not in application code after retrieval. Post-filtering leaks result counts, and in a hybrid pipeline it silently destroys your recall.

The short version

Search is infrastructure that behaves like a product feature, which is precisely why it ends up unowned. The teams that get it right in 2026 are not the ones running the largest clusters. They are the ones who measured relevance, stayed on Postgres for as long as it made sense, added semantic retrieval only where keyword search genuinely failed, and treated their search endpoint as an interface for both humans and machines.

At REPTILEHAUS we build and rescue exactly this kind of infrastructure, from PostgreSQL retrieval architecture and hybrid search pipelines through to the AI and agent integrations that increasingly sit on top of them. If your search bar is the feature nobody wants to touch, get in touch and we will help you work out which rung of the ladder you actually need.

📷 Photo by Jan Antonin Kolar on Unsplash