Define Duplicate, Similar and Acceptably Different
A similarity and deduplication service is like a librarian deciding whether a newly delivered book is already in the catalogue. An identical barcode is easy; a revised cover, corrected spelling, reordered paragraph, or resized image requires evidence. The service turns each item into comparable features, retrieves a small candidate set, verifies candidates with a declared similarity rule, and records a decision rather than comparing every new item with everything ever seen.
Take two token sets: A={red, fox, runs, fast} and B={red, fox, runs, today}. Their intersection has 3 elements and their union has 5, so Jaccard similarity is 3/5 = 0.60. If policy says “near duplicate at 0.80 or above,” they are acceptably different even though an approximate signature might place them in the same candidate bucket. Conversely, failing to generate a true candidate is a false negative that exact reranking cannot repair.
A shingle is a contiguous token or character sequence, such as word bigram red fox. A set signature such as MinHash estimates Jaccard similarity; a vector signature such as SimHash approximates angular similarity. Locality-sensitive hashing (LSH) groups likely neighbours into shared buckets. A membership filter can cheaply say “definitely unseen” or “possibly seen” under its contract. Verification computes the authoritative business metric over retained canonical features. The index lifecycle covers insert, tombstone, compaction, rebuild, migration, and rollback.
Stakeholders include content owners, storage engineers, search/recommendation teams, abuse analysts, privacy reviewers, and operators. Acceptance requires versioned normalization and signatures, tenant isolation, bounded candidate counts and memory, deterministic replay, measured recall at the decision threshold, exact verification before destructive action, explainable outcomes, and reversible merges or quarantines.
Approximate methods answer “which items should we compare?”; they do not decide that two items are duplicates. A destructive deduplication decision requires an exact, policy-versioned verification step or explicit human review.
| Term | Intuitive meaning | Exact example | Non-example | Assumption | Question answered |
|---|---|---|---|---|---|
| Normalization | Stable canonical representation | Unicode NFC, lowercase, whitespace collapse | Removing all numbers without policy | Version is fixed and auditable | What differences should be ignored? |
| Shingle | Local feature from content | Word bigram red fox | Whole document ID | Tokenization and width are stable | Which local fragments overlap? |
| Jaccard similarity | Set overlap divided by union | 3/5 = 0.60 | Cosine of term counts | Presence/absence features are intended | How similar are two shingle sets? |
| MinHash | Compact Jaccard estimator | Equal minima in 78 of 100 rows ≈ 0.78 | Cryptographic content hash | Hashes behave independently enough | Which set pairs are likely similar? |
| SimHash | Compact angular signature | Hamming-near fingerprints | Exact byte equality | Feature weights and bit hash are stable | Which weighted vectors point similarly? |
| LSH candidate | Pair worth exact comparison | Two IDs sharing a MinHash band | Confirmed duplicate | Band parameters match index version | Whom should we compare? |
| Membership filter | Cheap pre-check | “Definitely not in exact-ID set” | Proof that content is unique | False-positive/no-false-negative contract holds | Can work be skipped safely? |
| Exact reranking | Authoritative score and policy | Jaccard 0.91 ≥ τ=0.85 | LSH bucket collision | Canonical features remain available | Does this pair meet the decision rule? |
| Tombstone | Reversible index deletion marker | ID excluded until compaction | Immediate physical erasure everywhere | Replicas observe ordered epochs | Should an old item remain discoverable? |
Define Duplicate, Similar and Acceptably Different
Compare A={red, fox, runs, fast}, B={red, fox, runs, today}, and C={database, backup}. Checkpoint 1: A∩B has 3 elements and A∪B has 5, so J(A,B)=0.60. Checkpoint 2: A∩C=∅, hence J(A,C)=0. With candidate threshold 0.50 and duplicate threshold 0.80, B should be retrieved for A but must remain distinct after verification; C need not be a candidate. Expected outcome: no duplicate links. Reflection: why would treating candidate threshold 0.50 as the final decision cause destructive false positives?
Design the Signature and Candidate Pipeline
The service accepts up to 20,000 documents per second across isolated tenants, with 10 million active items per large tenant, candidate lookup below 50 ms p99, final decision below 200 ms p99, and a fixed per-item index budget. Producers send {tenant_id, item_id, content_uri, media_type, source_time, normalization_version, idempotency_key}. The gateway authenticates, validates size/type, resolves governed content, and writes a replayable command. Content is normalized, shingled, signed, optionally screened by compact filters, inserted into versioned LSH bands, and verified against a capped candidate set.
For text, word or character shingles feed 128-row MinHash; 32 bands of 4 rows give candidate probability 1-(1-s^4)^32 at true Jaccard similarity s. Parameters are calibrated from a labelled corpus rather than selected by folklore. SimHash is available for weighted bag-of-feature cosine-like workloads, but not mixed silently with MinHash. Exact Jaccard verification uses retained canonical shingle sets or a governed feature store. Every result reports candidate method/version, exact score, threshold/policy version, explanation, and decision state.
Privacy limits prohibit cross-tenant candidate generation, restrict raw-content access, encrypt features and snapshots, minimize retained shingles, and audit reviews. The threat model includes adversarial token stuffing, hash flooding, oversized content, crafted bucket explosions, duplicate command replay, malicious feedback, poisoned thresholds, snapshot tampering, and operator credential misuse. Resource guards cap shingles, candidates, buckets per item, verification bytes, and per-tenant index growth before allocation.
flowchart TD
P[Content producers] --> G[Auth validate quota]
G --> N[Normalize and shingle]
N --> S[MinHash or SimHash]
S --> F[Compact membership screen]
F --> L[Versioned LSH index]
L --> C[Bounded candidates]
C --> V[Exact verifier]
V --> D[Keep link or review]
D --> X[Index and decision log]
O[Operators] --> R[Policies rollout feedback]
R --> V
X --> M[Metrics traces audit]
classDef navy fill:#17365D,color:#fff,stroke:#102844;
classDef teal fill:#147D84,color:#fff,stroke:#0c5c61;
classDef crimson fill:#C6284D,color:#fff,stroke:#8e1935;
classDef purple fill:#6C3BAA,color:#fff,stroke:#482675;
class P,O navy;
class G,N,S,F teal;
class L,C,X purple;
class V,D,R,M crimson;
| Candidate | Guarantee | Scale / latency | Memory | Operational burden | Privacy | Recovery | Decision |
|---|---|---|---|---|---|---|---|
| All-pairs exact Jaccard | Exact under canonical features | O(N) comparisons per insert | Stores all features | Simple logic, impossible scale | Broad feature access | Rebuild from features | Keep as small-corpus oracle only |
| Exact content hash | Exact byte/canonical equality | O(1) lookup | One digest/item | Low | Digest can reveal known content | Replayable map | Select as first exact-duplicate tier |
| MinHash + banded LSH | Probabilistic candidate recall for Jaccard | Sublinear retrieval; tunable bucket work | Signatures + postings | Calibrate bands and versions | Signatures may leak resemblance | Rebuild versioned index | Select for set-based near duplicates |
| SimHash + Hamming search | Angular-near weighted features | Fast for short fingerprints | Fingerprint + multi-index | Radius explosion at high distance | Fingerprint leakage | Rebuild by version | Select only for vector-like workloads |
| Bloom/Cuckoo filter | Cheap membership screen; configured errors | Constant expected work | Fixed/bounded | Capacity and deletion semantics | Membership inference risk | Rebuild from authoritative IDs | Select as optimization, never final evidence |
| LSH-only decision | Bucket collision only | Fastest | Small | Hidden false positives | Minimal verification access | Easy | Reject: candidates are not decisions |
| LSH + exact reranking | Measured retrieval recall plus exact policy score | Bounded candidate verification | Index + canonical features | More components, auditable | Least raw access compatible with proof | Replay index; preserve decisions | Select as production architecture |
| Learned embedding ANN | Semantic proximity, model-dependent | High recall at tuned cost | Dense vectors + ANN graph | Model drift and GPU/index lifecycle | Embeddings may encode sensitive data | Versioned full rebuild | Roadmap after labelled-policy evidence |
The central invariant is that a candidate generator may only broaden or narrow the verification workload; it can never authorize deletion or merging. Launch requires tenant-isolated, version-compatible indexes, capped candidate work, measured recall, exact policy verification, idempotent decisions, and reversible outcomes.
Build Indexing, Verification and Feedback Loops
Build vertical slices. Slice 1 normalizes text, calculates an exact content hash, and compares every small-corpus item with exact Jaccard. Slice 2 adds deterministic MinHash and an LSH candidate index while retaining the oracle. Slice 3 introduces compact membership filters, partitioning, snapshots, tombstones, and rebuilds. Slice 4 adds policy decisions, explanations, reviewer feedback, and a shadow index for migrations. Each slice demonstrates ingest, query, verification, deletion, restore, and rollback independently.
Stable interfaces are upsert(item), candidates(item, limit), verify(left,right,policy), decide(item), tombstone(id,epoch), snapshot(), and restore(bytes). Configuration validates shingle size, signature length, band divisibility, threshold range, maximum shingles/candidates/bucket size, seeds, and format version before allocating. Serialized state records normalization, hash, signature, LSH, and policy versions plus tenant, epoch, checksum, and encryption metadata. Unsupported migrations rebuild from canonical features rather than coercing state.
Feedback is evidence, not truth by fiat. Reviewer labels are immutable events with actor, rationale, policy, and source versions. They feed threshold evaluation and labelled regression sets only after quality checks. Safe degradation can run exact-hash-only mode, quarantine a result, or reject over-budget content. It must not silently lower the threshold, cross tenant boundaries, or convert “no candidate found” into proof of uniqueness.
flowchart TD
C[Contracts and exact hash] --> O[All-pairs Jaccard oracle]
O --> S[Deterministic signatures]
S --> L[LSH candidate index]
L --> V[Exact policy verifier]
V --> I[Lifecycle and snapshots]
I --> F[Reviewed feedback loop]
F --> K[Shadow index canary]
K -->|Recall and SLO pass| P[Promote version]
K -->|Regression or drift| R[Rollback index]
R --> O
classDef navy fill:#17365D,color:#fff,stroke:#102844;
classDef teal fill:#147D84,color:#fff,stroke:#0c5c61;
classDef crimson fill:#C6284D,color:#fff,stroke:#8e1935;
classDef purple fill:#6C3BAA,color:#fff,stroke:#482675;
class C,O navy;
class S,L,V,I teal;
class F,K purple;
class P,R crimson;
Build Indexing, Verification and Feedback Loops: Similarity & Deduplication Service
Create normalize.py, signatures.py, index.py, verify.py, and test_replay.py. Insert A=red fox runs very fast; checkpoint 1 records four word-bigram shingles. Insert B=red fox runs very fast today; checkpoint 2 expects exact Jaccard 4/5=0.80 and a duplicate decision at threshold 0.75. Insert unrelated C=database backup completed nightly; expect no verified match. Re-run with the same seed and require byte-identical signatures. Compare LSH candidates with all-pairs exact results over a fixed labelled corpus, then rebuild a shadow index from the event log and compare postings. Try 31 rows with 8 bands, reuse an item ID, exceed the shingle cap, corrupt a snapshot, and mix normalization versions; all must fail before visible mutation. Done means deterministic replay, measured candidate recall, exact decisions, bounded work, lifecycle recovery, and auditable feedback pass in one command.
Measure Recall, Cost and Adversarial Failures
Verification treats candidate recall and decision precision as separate contracts. Unit tests cover normalization, shingle boundaries, deterministic hashing, band slicing, exact scoring, idempotency, tombstones, and serialization. Property tests assert Jaccard symmetry and bounds, identical inputs score 1, signature equality estimates set similarity across seeds, compatible rebuilds reproduce postings, and tenant IDs never share buckets. Differential replay compares LSH candidates and final decisions with all-pairs exact oracles on manageable corpora.
The approachable case uses A, B, and C from the build exercise. The professional workload contains 10 million items per large tenant, 20,000 inserts/s, multilingual text, templated pages, OCR noise, boilerplate, adversarial token padding, and labelled duplicate clusters near the threshold. Targets are candidate recall ≥99.5% for exact Jaccard ≥0.85, verified-decision precision ≥99.9%, candidate p99 <50 ms, end-to-end p99 <200 ms, availability ≥99.9%, candidate cap ≤100, and a published cost per million items.
Fault injection kills an indexer during checkpoint, delays a partition, corrupts postings, rotates a seed without a version bump, fills one hot bucket, removes the feature store, replays commands, and poisons feedback labels. Metrics expose ingest lag, bucket size, candidates/query, cap rejections, verification score distribution, labelled recall/precision, shadow-index disagreement, tombstone lag, snapshot age, and cross-version attempts. Traces connect normalization, signature, bands, candidate reads, exact verification, and decision. Audit evidence preserves policy/version, reviewer action, explanation, rollback, and content-access purpose.
| Requirement / guarantee | Oracle | Workload | Metric and threshold | Failure injection | Evidence | Owner |
|---|---|---|---|---|---|---|
| Normalization is deterministic | Golden canonical strings | Unicode, punctuation, OCR cases | Byte-identical output for a version | Locale/library change | Golden diff and dependency lock | Text pipeline owner |
| Candidate recall is adequate | All-pairs exact Jaccard | Labelled threshold-near corpus | Recall ≥99.5% for Jaccard ≥0.85 | Seed/band mismatch | Recall curve by cohort/version | Algorithms reviewer |
| Final decisions are precise | Human-reviewed/exact policy labels | Duplicate and hard-negative pairs | Precision ≥99.9%; no LSH-only decision | Verifier unavailable | Decision audit and confusion matrix | Product owner |
| Work remains bounded | Candidate and allocator counters | Hot templates, token stuffing | Candidate cap ≤100; reject before memory breach | Bucket explosion | Cap metrics and heap profile | Platform lead |
| Latency SLO | Load-generator clock | 20k inserts/s, 10M-item tenant | Candidate p99 <50 ms; total p99 <200 ms | Slow shard and feature store | Dashboard and traces | SRE |
| Version isolation | Compatibility oracle | Dual-write migration | Zero mixed signatures/policies | Seed rotation without version bump | Rejection logs and shadow diff | Index owner |
| Lifecycle correctness | Event-log replay | Upsert, tombstone, compact, rebuild | Rebuilt active set and postings match oracle | Crash during compaction | Replay hashes and tombstone audit | Storage owner |
| Recovery is safe | Snapshot checksum + replay | Indexer loss during checkpoint | RTO <30 min; corrupt state quarantined | Kill process, flip posting byte | Recovery timeline | Incident commander |
| Tenant/privacy isolation | Authorization oracle | Cross-tenant and sensitive-content probes | Zero cross-tenant candidates; all raw access audited | Forged tenant token | Security report and audit export | Security owner |
| Feedback resists poisoning | Curated reviewer consensus | Conflicting and burst labels | Untrusted labels never auto-change policy | Compromised reviewer account | Label lineage and approval record | Governance owner |
Measure Recall, Cost and Adversarial Failures: Similarity & Deduplication Service
Run a 40-minute trial over a labelled multilingual corpus with exact duplicates, paraphrase-like non-duplicates, OCR noise, boilerplate, and pairs concentrated around Jaccard 0.85. Ramp from 5k to 20k then 30k inserts/s while querying a 10M-item tenant. Require candidate recall ≥99.5% for true score ≥0.85, decision precision ≥99.9%, candidate p99 <50 ms, total p99 <200 ms, candidates ≤100, and zero tenant/version violations. At minute 12 create a hot template bucket; expect bounded quarantine. At minute 20 kill an indexer during checkpoint; expect replay recovery. At minute 28 corrupt postings and rotate a seed without a version bump; expect checksum/compatibility rejection and shadow disagreement alerts. Roll back on any destructive false positive, isolation failure, recall below target, sustained p99 >300 ms, or unsafe cap bypass. Record GO, CONDITIONAL GO, or NO-GO with curves, traces, replay hashes, cost per million items, named owners, and expiry dates.
Deliver the Deduplication Service
The release bundle contains API and event schemas, normalization and feature specifications, signature/LSH parameter calculators, policy examples, a pinned environment, labelled datasets and lineage, benchmark commands and raw results, the correctness dossier, migration matrix, privacy/security review, dashboards, alerts, and an operational runbook. Every artifact states version, owner, generation command, review date, and retention rule.
The runbook begins with symptoms—candidate explosion, recall drift, latency, index disagreement, tombstone lag, feature-store outage, mixed versions—and maps each to diagnostics, thresholds, safe degradation, escalation, rollback, and evidence preservation. The demonstration normalizes A/B/C, shows exact hashes and shingles, retrieves B as A's candidate, verifies 4/5, keeps C distinct, rejects an incompatible layout, tombstones and rebuilds an item, and finishes with labelled recall/cost dashboards.
Peer reviewers ask: Which differences does normalization erase? Can candidate recall be reproduced by cohort? Is every destructive outcome exactly verified and reversible? What happens when canonical features are unavailable? Can a hot bucket cross the resource budget? Are feedback labels governed? Could signatures reveal sensitive content? Handoff requires a tagged build, checksums, one-command verification, benchmark provenance, signed correctness/privacy dossiers, rehearsed rebuild/rollback, on-call ownership, and no undocumented bypass.
Deliver the Deduplication Service: Similarity & Deduplication Service
Final checklist: (1) build from a clean checkout; (2) run unit, property, labelled replay, load, security, and fault suites; (3) publish schemas, normalization, thresholds, and explanations; (4) attach banding calculations and recall/precision curves; (5) archive corpora lineage, seeds, environment lock, commands, and raw benchmarks; (6) sign correctness, privacy, and feedback-governance dossiers; (7) rehearse rebuild, tombstone recovery, quarantine, and rollback; (8) confirm dashboard, alert, and on-call ownership. Demo A/B/C, candidate-versus-decision separation, exact score, cap rejection, incompatible-version rejection, checkpoint recovery, and shadow-index comparison. Score 0–2 for correctness, retrieval quality, contract clarity, reproducibility, bounded resources, observability/recovery, privacy/governance, and documentation; require ≥14/16 with no zero. Stretch goals: multimodal perceptual hashes, learned embeddings, active-learning review queues, and privacy-preserving signatures. Milestones: cohort calibration, dual-index migration automation, then governed multimodal matching.
Launch only with measured candidate recall, exact and reversible decisions, bounded work, version isolation, privacy controls, and rehearsed rebuild/rollback. Known risks include normalization bias, adversarial collisions, signature leakage, reviewer poisoning, and unequal error rates across languages; ask who bears the cost of a false merge, then make cohort-level calibration and appeal evidence the next milestone.