windlass.providers.preprocessors.dedup¶
dedup
¶
Deduplication and table extraction.
Real corpora are full of duplicates: the same policy PDF exported three times, boilerplate footers repeated on every page, near-identical release notes. Duplicates waste embedding spend, and worse, they crowd the top-k so a single document can fill the entire context window.
DeduplicatePreprocessor removes exact duplicates by content hash and
near-duplicates by MinHash-style shingle similarity — no dependencies, one pass.
Example
from windlass.core.types import Document docs = [Document(content="same text here"), Document(content="Same text here")] len(DeduplicatePreprocessor().process(docs)) 1
DeduplicatePreprocessor
¶
DeduplicatePreprocessor(
*,
threshold: float = 0.9,
shingle_size: int = 5,
keep: str = "first",
min_words: int = 20,
**config: Any
)
Bases: Preprocessor
Removes duplicate and near-duplicate documents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
threshold
|
float
|
Jaccard similarity at or above which two documents are
considered duplicates. |
0.9
|
shingle_size
|
int
|
Words per shingle for near-duplicate comparison. |
5
|
keep
|
str
|
|
'first'
|
min_words
|
int
|
Documents shorter than this skip near-duplicate comparison, since short texts collide spuriously. |
20
|
**config
|
Any
|
Forwarded to :class: |
{}
|
Raises:
| Type | Description |
|---|---|
ValueError
|
For an unknown |
Performance
Exact deduplication is O(n). Near-duplicate detection compares each
document against the survivors, which is O(n·k) where k is the
number of unique documents — fine for tens of thousands, and the reason
threshold=1.0 exists for much larger corpora.
Note
Unlike most preprocessors this one is corpus-level: it must see the
whole batch at once, so it overrides aprocess rather than
aprocess_one.
Source code in src\windlass\providers\preprocessors\dedup.py
aprocess_one
async
¶
aprocess
async
¶
Remove duplicates from a batch.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
documents
|
Sequence[Document]
|
The documents to deduplicate. |
required |
concurrency
|
int | None
|
Ignored — this step is inherently sequential. |
None
|
Returns:
| Type | Description |
|---|---|
list[Document]
|
The surviving documents, in input order, each tagged with how many |
list[Document]
|
duplicates it absorbed. |
Source code in src\windlass\providers\preprocessors\dedup.py
TableExtractPreprocessor
¶
Bases: Preprocessor
Separates tables from surrounding prose.
Tables and prose want different chunk sizes and retrieve on different signals. Splitting them lets a table stay whole (a half table is useless) while the prose around it is chunked normally.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mode
|
str
|
|
'split'
|
min_rows
|
int
|
Ignore tables with fewer rows than this. |
2
|
**config
|
Any
|
Forwarded to :class: |
{}
|
Raises:
| Type | Description |
|---|---|
ValueError
|
For an unknown |
Note
Operates on Markdown-style pipe tables, which is what the XLSX, DOCX and HTML loaders emit. Tables in a PDF's raw text layer are not reliably detectable and are left alone.
Example
from windlass.core.types import Document md = "Intro.\n\n| a | b |\n| --- | --- |\n| 1 | 2 |\n\nOutro." docs = TableExtractPreprocessor().process([Document(content=md)]) sum(1 for d in docs if d.metadata.get("content_type") == "table") 1
Source code in src\windlass\providers\preprocessors\dedup.py
aprocess_one
async
¶
Find tables and apply the configured mode.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
Document
|
The document to inspect. |
required |
Returns:
| Type | Description |
|---|---|
list[Document]
|
One or more documents depending on the mode. |
Source code in src\windlass\providers\preprocessors\dedup.py
shingles
¶
Return the set of hashed word n-grams in text.
Shingling is what makes near-duplicate detection work: two documents that differ by a sentence share almost all their shingles, while two unrelated documents share almost none.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to shingle. |
required |
size
|
int
|
Words per shingle. Smaller catches looser similarity; 5 is a good default for prose. |
5
|
Returns:
| Type | Description |
|---|---|
set[int]
|
Hashed shingles. Short texts return one shingle covering everything. |
Example
len(shingles("a b c d e f", size=3)) > 0 True
Source code in src\windlass\providers\preprocessors\dedup.py
jaccard
¶
Return the Jaccard similarity of two sets, in [0, 1].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
set[int]
|
First set. |
required |
right
|
set[int]
|
Second set. |
required |
Returns:
| Type | Description |
|---|---|
float
|
|
Example
jaccard({1, 2, 3}, {2, 3, 4}) 0.5