Diversifying Near-Duplicate Search Results
A top-five search can return five results containing only three distinct texts. This happens when a corpus contains documents copied for another environment, customer or version and edited only slightly.
The ranking can be correct for each result while the result set is still poor: several high-scoring slots carry the same information.
Why similarity cannot fix this
Near-copies have near-identical embeddings. That is what makes them near-copies. When a query matches one copy, it usually matches the others at almost the same score. A normal top-k selection evaluates every document independently, so it has no reason to reserve slots for different information.
Here is what that looks like on a runbook that was forked per environment:
0.95 runbooks/restart-env-0.md "restart the service by running systemctl…"
0.94 runbooks/restart-env-1.md "restart the service by running systemctl…"
0.93 runbooks/restart-env-2.md "restart the service by running systemctl…"
0.92 runbooks/restart-env-3.md "restart the service by running systemctl…"
0.90 runbooks/certificates.md "rotate the certificate with certbot renew…"
0.89 runbooks/scaling.md "scale the deployment by editing replicas…"
With topK: 4, all four slots describe the same restart procedure while the
other useful results remain below the cut.
What a keyword score does about it
TF-IDF and BM25 have the same limitation. Near-copies contain nearly the same terms at similar frequencies, so their scores tend to cluster together.
Both halves of hybrid search answer how well each document matches the query.
Neither measures how much new information a result adds to those already
selected, so alpha and rrf alone do not solve the problem.
Measuring textual overlap
The diversity signal measures how much text two documents share.
MDDB estimates this with MinHash. It splits each document into overlapping runs of three consecutive words and builds a 128-value signature. Agreement between two signatures estimates the Jaccard overlap of their shingle sets.
Building a signature depends on document length. Comparing two completed signatures takes a fixed 128 comparisons, regardless of the source documents' lengths.
The useful property is that textual overlap can disagree with semantic similarity:
| Pair | Expected embedding similarity | Example text overlap |
|---|---|---|
| A document and its own copy | Very high | 1.00 |
| A document with two words changed | Very high | 0.83 |
| Two independent pages on certificate rotation | High | 0.04 |
| Two unrelated pages | Low | 0.00 |
Two independently written pages about certificate rotation may be semantically close while sharing few three-word sequences. MinHash can therefore separate a copied page from another page about the same subject.
Our test for it is named after that:
func TestSameTopicDifferentWordsScoresLow(t *testing.T)
The signal
MDDB 2.12 adds a weighted fusion strategy: alpha's blend, then adjusted by
signals the base fusion cannot see.
curl -s -X POST "$MDDB/v1/hybrid-search" -d '{
"collection": "runbooks",
"query": "restart the service",
"strategy": "weighted",
"signals": { "diversity": 0.8 }
}'
Each result is compared against every result already ranked above it. If it overlaps one of them past the threshold, its score is reduced in proportion to the overlap — a heavy rewrite is demoted slightly, a verbatim copy heavily.
flowchart LR
Q[Query] --> B["Base fusion
keyword + vector"]
B --> R1["1. restart-env-0 0.95"]
R1 --> R2["2. restart-env-1 0.94"]
R2 --> D{"Overlaps a
higher result?"}
D -->|"0.91 ≥ 0.5"| P["penalise
0.94 → 0.25"]
D -->|no| K[keep]
P --> S[Re-sort]
K --> S
S --> F["1. restart-env-0
2. certificates
3. scaling
4. drain-node"]
Measured on exactly the corpus above — one document forked four ways plus three distinct answers:
| Distinct documents in the top 4 | |
|---|---|
| Without the signal | 1 |
diversity: 0.8 |
4 |
In this test, the signal changes the top four from one distinct answer to four.
Weight and freshness defaults
A weight is a fraction of the score. proximity: 0.1 means "up to 10%
better". An early test used 0.5, which allowed a shared directory to outweigh
a much stronger base score. Weights are now documented, clamped to [0, 1], and
covered by a test for that aggressive setting.
Freshness is off by default, and should stay off for reference material. An API specification does not become less true with age, and a decay curve does not know that.
Near-duplicate detection
The same overlap estimate is also available for near-duplicate detection.
MDDB already had two duplicate modes. exact compares content hashes, so a
one-byte change produces a different hash. similar requires an embedding
provider and primarily measures topic, which makes it less suitable for
distinguishing a copied document from an independently written page about the
same procedure.
curl -s -X POST "$MDDB/v1/find-duplicates" -d '{
"collection": "runbooks",
"mode": "minhash",
"threshold": 0.7
}'
This mode finds copied-and-edited documents without treating independently written pages on the same topic as duplicates. It does not require embeddings. The ranking signal and duplicate endpoint share the same MinHash package.
MinHash is not included in mode: "both". Unlike the other two modes, it reads
every document body, so enabling it implicitly could make an existing request
substantially more expensive.
When to reach for it
Diversity is useful for templates filled in per customer, runbooks forked per environment, documentation versioned by copying, and content received through multiple imports.
It can remain off for collections where documents are independently authored and result diversity is not a problem. When enabled, MDDB computes one MinHash signature per result in the merge window and reuses it for every comparison.
Reference: search algorithms, section Weighted (multi-signal
fusion). The other two signals — proximity and freshness — are documented
there, along with the signalBreakdown the response carries, so what each one
contributed is visible rather than inferred.