What semantic search is
Keyword search asks which documents contain these words. Semantic search asks which documents mean something close to this. A support corpus that says rate limit is found by a customer who types throttled, because their embeddings are near each other even though the words differ.
It is the default retrieval method in RAG demos because it handles natural-language questions well and needs no synonym lists or query rewriting.
Under the hood it is nearest-neighbour search over embeddings. The quality of results therefore depends on three things: the embedding model, how the documents were chunked before embedding, and how many candidates the index is allowed to consider. A strong model cannot rescue chunks that start and end mid-sentence.
How it works
- At ingest, each chunk of text is embedded and stored in a vector index.
- At query time, the query is embedded with the same model.
- An approximate nearest-neighbour search (commonly HNSW) finds the stored vectors with the highest cosine similarity.
- The matching chunks are returned, ranked by similarity.
k is how many neighbours come back; num_candidates is how many nodes the graph walk considers. Set the candidate count too low and recall drops silently: documents in the index stop appearing and nothing logs an error.
Where semantic search fails
- Literals. Version numbers, error codes, product SKUs and API key prefixes. A search for
ECONNRESETreturns passages about errors rather than the line containing the string. - It always returns something. Nearest-neighbour search has no notion of no match. Ask a crawl-docs corpus about football and you get the ten least-distant chunks, with nothing saying they are irrelevant.
- Generic text wins too often. Short boilerplate and error pages embed near the middle of the space and show up for many queries.
- Rare terms and new jargon. Words the model saw little of in training embed poorly.
Dense vectors are good at meaning and bad at literals. That is why production search runs a keyword leg beside them.
The fix is hybrid search: run BM25 and vector search together and merge them with reciprocal rank fusion.
None of these are reasons to drop semantic search. They are reasons not to run it alone. A useful habit is to keep a short list of real queries that must work, including at least one exact identifier and one question the corpus cannot answer, and run it after every change to the model, the chunking or the index settings.
How SarvCrawl handles it
SarvCrawl offers keyword search and semantic search on every knowledge base, and its embed-search endpoint runs both legs and fuses them with reciprocal rank fusion. The vector leg over-fetches a candidate pool rather than asking for exactly the number of results, chunks under 100 tokens are excluded so error pages cannot crowd in, and the response reports knn_score, bm25_score and match_via for each hit.
When nothing matched on keywords and the best cosine similarity is under 0.25, the response sets low_confidence: true, so an agent can decline instead of answering from irrelevant chunks. Search is available on paid plans; see the search API and embed-search docs.
Frequently asked questions
Is semantic search the same as vector search?
In practice the terms are used interchangeably. Vector search is the mechanism, nearest-neighbour lookup over embeddings; semantic search is the goal, matching by meaning.
Is semantic search better than keyword search?
Neither is better overall. Semantic search wins on paraphrased questions, keyword search wins on exact strings like codes and names. Combining them beats either alone.
Why does semantic search return irrelevant results?
Because nearest-neighbour search always returns the closest vectors, even when none are close. Use a similarity floor, a keyword-match check, or both to detect when nothing relevant exists.