New1 billion tokens free on sign-up — crawl, parse, chunk and embed on the houseSee pricing
SarvCrawlSarvCrawl

Glossary · Extraction and parsingUpdated

What is near-duplicate detection?

Near-duplicate detection finds documents that are almost but not exactly identical, such as a page and its print version or two locale variants that differ only in navigation, so they can be removed or merged before indexing.

01What near-duplicates areof 05

What near-duplicates are

Crawl any large site and a share of what comes back is the same content under a different address. Exact duplicates are easy to catch. Near-duplicates are the residue: pages that are 95% the same.

  • Locale variants where only the navigation was translated.
  • API reference pages generated from one template for forty endpoints.
  • A print version of every article.
  • Versioned docs, /v1/, /v2/ and /v3/, with small edits between them.
  • Pages that differ only by a timestamp, a related-posts block or a session id.

They are the duplicates that hurt retrieval most. They cluster tightly in embedding space and crowd out genuine variety in the top results, so a model is handed one source and the illusion of five.

Exact hashing does not catch them, because a single changed character produces a completely different hash.

How it works

Deduplication works best at three levels, each catching what the last cannot:

  1. URL normalisation, before fetching: strip tracking parameters and fragments, unify trailing slashes and case, respect rel=canonical. Cheapest, because it prevents the request.
  2. Exact content hashing, after fetching: SHA-256 of the extracted text, not the raw HTML, which differs on every render.
  3. Near-duplicate detection: compare sets of overlapping word sequences.

The usual technique is shingling: split text into overlapping runs of k words and compare the sets with Jaccard similarity. Comparing every pair is too slow at scale, so MinHash compresses each set into a short signature whose agreement estimates Jaccard, and locality-sensitive hashing buckets likely matches. SimHash is an alternative that produces a single fingerprint where similar texts differ in few bits.

def shingles(text, k=5):
    words = text.lower().split()
    return {" ".join(words[i:i + k]) for i in range(len(words) - k + 1)}

def jaccard(a, b):
    return len(a & b) / len(a | b) if a | b else 1.0

if jaccard(shingles(page_a), shingles(page_b)) > 0.9:
    print("near-duplicate")

Common pitfalls

  • Hashing HTML. CSRF tokens, build hashes and footer years change on every render, so no two fetches match. Hash the extracted text.
  • Comparing whole pages including boilerplate. Shared navigation and footers make unrelated pages look similar. Extract main content first.
  • Threshold too low. Legitimately different pages from one template, say two product pages, can be merged by mistake. Inspect matches before deleting.
  • Deduplicating versions blindly. /v2/ and /v3/ may be near-identical yet differ in exactly the line that matters. Usually the right move is to exclude old versions at crawl time.

URL normalisation saves money. Near-duplicate detection saves your search results.

How SarvCrawl handles it

In SarvCrawl the first line of defence is the crawl itself: exclude_paths keeps version archives, locale prefixes, tag pages and changelogs out of a knowledge base, and a map of the site first shows which directories are worth crawling. Pages are stored as clean markdown rather than raw HTML, so render-to-render noise such as tokens and build hashes does not make one page look like many.

At query time, hybrid search caps how many chunks any one page can contribute to a result, two for five or fewer results and three otherwise, so near-identical chunks cannot fill the top of the list. The full three-level approach is in build a RAG knowledge base from a documentation site.

Frequently asked questions

What is the difference between duplicate and near-duplicate detection?

Duplicate detection finds byte-identical or text-identical content, usually with a hash. Near-duplicate detection finds content that is mostly the same, using similarity measures such as Jaccard over shingles, MinHash or SimHash.

What similarity threshold should I use?

It depends on the corpus. High thresholds around 0.9 Jaccard are a common starting point; check a sample of matches before removing anything.

Why do near-duplicates hurt RAG?

They retrieve together for the same queries and fill the top results with one source, pushing out other relevant documents and giving the model false corroboration.

SarvCrawl

Turn any site into a searchable knowledge base

Crawl pages and parse documents into clean markdown, then chunk, embed and search them from one API.