From Character Edits to Semantic Vectors: How Text Similarity Search Evolved
How search engineering moved from counting character edits to mapping human intent — and why every era of the stack still earns its place…
From Character Edits to Semantic Vectors: How Text Similarity Search Evolved
How search engineering moved from counting character edits to mapping human intent — and why every era of the stack still earns its place in production.

Three generations of similarity: edit operations on characters, weighted token overlap, and proximity in learned vector space.
Imagine you are building the search functionality for an e-commerce storefront.
A customer types laptop sleeve into the search bar
Deep within your catalog, the exact product they want is listed as
“13-inch Notebook Case.”
If your search service relies on traditional exact-string matching, the customer is met with an empty results page — and you lose the sale.
To a computer, “laptop sleeve” and “notebook case” share zero words in common. To a shopper, however, they are the exact same product.
Bridging this gap — the chasm between literal character sequences and human meaning — is one of the oldest challenges in computer science. Over the last few decades, the way backend and search engineers reason about “text similarity” has fundamentally changed — from comparing characters to comparing meaning.
Crucially, this evolution is not a story of old technologies becoming obsolete. Rather, it is a story of how our definition of similarity expanded. We moved from measuring similarity at the character level, transitioned to tracking frequency at the word level, and ultimately arrived at mapping intent at the semantic level.

Understanding this trajectory is essential for any engineer designing modern software infrastructure. Each generation of similarity techniques solved a specific problem, introduced unique computational trade-offs, and remains a vital tool in the modern production stack today. This piece traces that lineage era by era: the constraint each generation hit, and the design the next generation answered it with.
1. The Era of Strict Determinism: Exact Matching
In the earliest days of software engineering, text similarity was a binary proposition. Two strings were either identical, or they were not.
From an infrastructure standpoint, this was incredibly efficient. Strings could be evaluated via byte-by-byte comparisons or run through cryptographic and non-cryptographic hashing algorithms (like MurmurHash or SHA-256). Checking if a user input matched a record in a database was an O(1) look-up using a hash table or a highly optimized index scan on a B-Tree.

The Breakdown of Exact Matching
While exact matching works perfectly for identifiers like UUIDs, Stock Keeping Unit (SKU) numbers, or email addresses, it fails immediately when confronted with human input. Humans are messy typists. They introduce trailing whitespaces, varied casing, punctuation discrepancies, and spelling errors.
For an application relying solely on exact matching, a single misplaced keystroke renders a record undiscoverable. To build resilient systems — such as e-commerce product catalogs or customer support routing engines — engineers needed a way to measure the degree of similarity between two non-identical strings.
2. When Similarity Meant Character Matching: Levenshtein Distance
To solve the fragility of exact matching, engineers turned to structural, character-based similarity metrics. The core objective shifted: if two strings are not identical, how many edits does it take to make them identical?
The foundational breakthrough in this space was the Levenshtein Distance (a type of Edit Distance), introduced in the mid-1960s — Vladimir Levenshtein’s seminal work was published in Russian in 1965 and translated into English in 1966.
The Mechanics of Edit Distance
Levenshtein distance quantifies the minimum number of single-character operations required to transform one string into another. The permitted operations are:
-
Insertion: adding a character (cat → cats)
-
Deletion: removing a character (cart → cat)
-
Substitution: replacing one character with another (cat → cot)
Consider transforming the misspelled search query “billling” into the valid database token “billing”. The algorithm identifies that removing one “l” yields a match, resulting in a Levenshtein distance of 1.
Mathematically, we compute this with dynamic programming. We construct a matrix where the rows represent one string and the columns the other, filling in the minimum edit costs progressively:

The DP matrix for billling → billing. The highlighted path absorbs the extra l as a single deletion; the bottom-right cell is the final edit distance: 1.
Engineering Trade-Offs and Real-World Use Cases
The transition to Levenshtein distance was a turning point because it replaced a boolean verdict with scalar similarity. Instead of a boolean true/false, engineers received an integer score. A distance of 1 or 2 indicated a highly probable typo; a distance of 10 indicated entirely different words.
However, this flexibility came with a steep computational cost. Computing the Levenshtein distance between two strings of length M and N requires O(M × N) time and space complexity.
Running an O(M × N) calculation against millions of rows in a relational database at query time is an architectural bottleneck. To mitigate this, search infrastructure engineers developed optimizations like Levenshtein Automata and character N-Grams.
Where It Shines Today
Levenshtein distance and its variants (like Jaro-Winkler or Hamming distance) remain heavily utilized in modern systems for localized, character-dependent tasks such as typo correction, data deduplication, and entity matching.
3. The Limits of Character-Based Similarity
While Levenshtein distance elegantly solved the problem of typos and minor structural changes, it proved fundamentally unequipped to handle a broader engineering challenge: document-level retrieval and vocabulary variation.
As software platforms scaled, engineers were no longer just comparing individual words or usernames. They were tasked with building search across entire customer support knowledge bases, internal wikis, and e-commerce descriptions.
In this context, character-level comparison breaks down completely. Consider three common scenarios in enterprise systems where meaning is aligned but the wording shares no structural overlap:

Same intent, zero structural overlap — character metrics confidently return the wrong answer.
If an engineer applies Levenshtein distance to evaluate the similarity between “payment failed” and “transaction declined,” the score indicates they are almost entirely unrelated. The edit distance is 14 — as long as the shorter string itself — because the algorithm treats characters as arbitrary symbols; it has no concept of what a “payment” or a “transaction” actually represents in the real world.
To index and search large bodies of text efficiently, the software industry needed to step away from individual characters and start analyzing text at the token (word) level.
4. The Lexical Era: TF-IDF and BM25
The limitations of character-level matching gave birth to the Lexical Era. The core engineering problem shifted from “how many character edits differentiate these strings?” to “which unique words do these documents share, and how important are those words?”
Instead of treating a document as an ordered sequence of characters, systems began treating documents as a Bag of Words — a collection of individual tokens, ignoring grammar and word order but focusing heavily on occurrence frequencies.
The Inverted Index: The Infrastructure Foundation
To make token-based search performant at scale, engineers built the Inverted Index. Instead of mapping a document to its content, an inverted index maps individual words to the list of document IDs where those words appear. This moved lookup times from slow linear scans back to highly efficient dictionary lookups.

Doc 1: “payment failed today” · Doc 2: “routing payment processed”. The index maps words → documents, so a query for “payment” instantly resolves to both.
Weighting Importance: TF-IDF
Simply matching words isn’t enough. TF-IDF (Term Frequency–Inverse Document Frequency) balances Term Frequency (how often a word appears in a specific document) with Inverse Document Frequency (how rare that word is across the entire collection). Common words like “the” score near zero; rare, discriminating words like “deadlock” score high.
score(t, d) = TF(t, d) × log( N / DF(t) )
The Reign of Okapi BM25
While TF-IDF was a major leap forward, it suffered from a scaling issue: if a word appeared 100 times in a long document, its score would explode linearly. To address this, the industry standardized on Okapi BM25 — the undisputed production standard inside tools like Lucene, Elasticsearch, and Solr.
BM25 achieved this longevity because it combines incredible query speed with absolute predictability, requiring zero training data and offering completely auditable scores. It refines raw TF-IDF with two vital mechanics:
1. Term Frequency Saturation (k₁): caps the influence of repeated words, recognizing that once a word appears a few times, subsequent occurrences offer diminishing returns on relevance.
- Document Length Normalization (b): penalizes exceptionally long, verbose documents so concise, targeted matches win.

The 100th occurrence of a keyword shouldn’t count like the 1st. BM25 flattens the curve; TF-IDF keeps climbing.
score(D, q) = IDF(q) × [ f(q, D) × (k₁ + 1) ]
/ [ f(q, D) + k₁ × (1 − b + b × |D| / avgdl) ]
A Worked Production Example of BM25
Suppose our index has an average document length (avgdl) of 100 words. We use the defaults k₁ = 1.2 and b = 0.75, and assume the IDF for the term deadlock is 2.5.

Score(A) = 2.5 × (2 × 2.2) / 2.48 = 4.435 · Score(B) = 2.5 × (15 × 2.2) / 19.8 = 4.166
Despite Document B having over 7× more mentions of the keyword, Document A wins because BM25’s length normalization penalizes the long log dump. This is exactly the behavior a production engineer wants: the focused incident write-up should outrank the noisy log file.
5. The Embedding Revolution: Dense Semantic Space
The lexical era proved that matching literal words was insufficient for capturing human intent. This catalyzed the Embedding Revolution — a lineage that began with word-level models like Word2Vec (2013) and GloVe, and matured into transformer-based sentence encoders that can represent an entire query or document as a single point in space.
What Is an Embedding?
An embedding transforms text into a fixed-size array of floating-point numbers — a dense vector, typically ranging from 384 to 1536 dimensions. The model projects text as a single coordinate point inside a high-dimensional mathematical space where spatial proximity correlates directly with conceptual similarity.

A 2-D projection of a ~768-dimension space. Phrases that share zero words sit nearly on top of each other — because the model learned they mean the same thing.
Measuring Proximity: Cosine Similarity
In the embedding era, engineers measure similarity by calculating the angle between two vectors with Cosine Similarity, which yields a metric bound between −1 and 1 based on directional alignment. Two vectors pointing in the same direction score near 1; orthogonal vectors score 0.
cos(A, B) = ( A · B ) / ( ‖A‖ × ‖B‖ )
payment failed” and “transaction declined” share zero characters — and nearly identical coordinates. The core promise of semantic search
6. Similarity Becomes Learned
The transition from BM25 to embeddings represents a profound philosophical shift: similarity transitioned from being engineered to being learned. Instead of writing rule-based scoring formulas, engineers architect systems that use learned representations generated by neural networks optimized over massive text corpora.
This shift also changes the operational profile. BM25 scores are deterministic and auditable; embedding scores are products of a trained model, which means quality now depends on the model’s training data, its domain coverage, and its versioning. Upgrading an embedding model is a re-indexing event, not a config change — a trade-off every team adopting semantic search must plan for.
7. From Embeddings to Vector Search: The Scale Challenge
With embeddings, every document is a continuous array of numbers. A brute-force linear scan across millions of high-dimensional vectors causes APIs to time out under production traffic.
The Rise of Approximate Nearest Neighbor (ANN) Search
To bypass computational limits, search engineers developed Approximate Nearest Neighbor (ANN) algorithms, such as Hierarchical Navigable Small World (HNSW). HNSW constructs a multi-layered graph structure that allows roughly logarithmic O(log N) traversal, letting vector databases serve semantic search queries across billions of records in milliseconds.

HNSW descends from a sparse “highway” layer to dense local layers — a logarithmic route to the nearest vector instead of a full scan.
8. Why This Matters for Modern Enterprise Infrastructure: RAG and Hybrid Search
The evolution of text similarity forms the structural foundation behind Retrieval-Augmented Generation (RAG): convert the user’s query to an embedding, retrieve the closest document chunks via ANN search, and pass them into a large language model as grounded context. The retrieval layer decides what the model gets to read — which is why every era in this article quietly shapes RAG quality. For a hands-on, code-level tour of that exact pipeline, see our publication’s companion piece, ***RAG, BM25, and Embeddings: How AI Tools Find the Right Context.***
Hybrid Search in Practice
Pure embedding search struggles with strict technical identifiers like product SKUs or error codes. Modern systems resolve this via Hybrid Search: running a BM25 lexical search and a vector embedding search simultaneously, then merging the results using Reciprocal Rank Fusion (RRF).

A hybrid RAG retrieval pipeline. BM25 nails the exact error code; the vector path understands the paraphrase; RRF reconciles the two ranked lists.
We will stop at the architecture level here: the fusion formula, the weighting knobs, and a live experiment with both retrievers belong to the companion piece linked above — that is its home turf.
The Engineer’s Decision Framework

Pick the level of similarity the problem actually requires — not the newest one available.
9. The Blueprint Comparison
The journey of text similarity highlights a steady shift from processing text to approximating meaning. Yet an algorithm is never truly obsolete. A 768-dimensional embedding model is a powerful tool for discovering semantic intent, but it is a highly inefficient way to verify a user’s password or look up an exact database primary key.

The blueprint: every layer of the stack still has a job — the art is matching the layer to the problem.
The art of software engineering lies in recognizing where a problem sits on this evolutionary spectrum — and choosing the exact level of similarity needed to solve it.
If problems like hybrid search and retrieval infrastructure excite you, we’re hiring — come build with us.

메타데이터
- post_id
- 9d52fb0d88d6
- slug
- from-character-edits-to-semantic-vectors-how-text-similarity-search-evolved-9d52fb0d88d6
- url
- https://medium.com/insiderengineering/from-character-edits-to-semantic-vectors-how-text-similarity-search-evolved-9d52fb0d88d6
- canonical_url
- https://medium.com/insiderengineering/from-character-edits-to-semantic-vectors-how-text-similarity-search-evolved-9d52fb0d88d6
- author_url
- https://medium.com/@taha.caba
- status
- ok
- fetched_at
- 2026-08-01 14:19:49