chore: import upstream snapshot with attribution
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
Docker image release / Build base image (push) Has been cancelled
Sync docs with Docusaurus / sync (push) Has been cancelled
Tests / Check if changed (push) Has been cancelled
Tests / format (push) Has been cancelled
Tests / check-imports (push) Has been cancelled
Tests / Unit / macos-latest (push) Has been cancelled
Tests / Unit / ubuntu-latest (push) Has been cancelled
Tests / Unit / windows-latest (push) Has been cancelled
Tests / mypy (push) Has been cancelled
Tests / Integration / ubuntu-latest (push) Has been cancelled
Tests / Integration / macos-latest (push) Has been cancelled
Tests / Integration / windows-latest (push) Has been cancelled
Tests / notify-slack-on-failure (push) Has been cancelled
Tests / Mark tests as completed (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:22:28 +08:00
commit c56bef871b
9296 changed files with 1854228 additions and 0 deletions
@@ -0,0 +1,190 @@
---
title: "ChineseDocumentSplitter"
id: chinesedocumentsplitter
slug: "/chinesedocumentsplitter"
description: "`ChineseDocumentSplitter` divides Chinese text documents into smaller chunks using advanced Chinese language processing capabilities. It leverages HanLP for accurate Chinese word segmentation and sentence tokenization, making it ideal for processing Chinese text that requires linguistic awareness."
---
# ChineseDocumentSplitter
`ChineseDocumentSplitter` divides Chinese text documents into smaller chunks using advanced Chinese language processing capabilities. It leverages HanLP for accurate Chinese word segmentation and sentence tokenization, making it ideal for processing Chinese text that requires linguistic awareness.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) and [DocumentCleaner](documentcleaner.mdx), before [Classifiers](../classifiers.mdx) |
| **Mandatory run variables** | `documents`: A list of documents with Chinese text content |
| **Output variables** | `documents`: A list of documents, each containing a chunk of the original Chinese text |
| **API reference** | [HanLP](/reference/integrations-hanlp) |
| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/hanlp |
| **Package name** | `hanlp-haystack` |
</div>
## Overview
`ChineseDocumentSplitter` is a specialized document splitter designed specifically for Chinese text processing. Unlike English text where words are separated by spaces, Chinese text is written continuously without spaces between words.
This component leverages HanLP (Han Language Processing) to provide accurate Chinese word segmentation and sentence tokenization. It supports two granularity levels:
- **Coarse granularity**: Provides broader word segmentation suitable for most general use cases. Uses `COARSE_ELECTRA_SMALL_ZH` model for general-purpose segmentation.
- **Fine granularity**: Offers more detailed word segmentation for specialized applications. Uses `FINE_ELECTRA_SMALL_ZH` model for detailed segmentation.
The splitter can divide documents by various units:
- `word`: Splits by Chinese words (multi-character tokens)
- `sentence`: Splits by sentences using HanLP sentence tokenizer
- `passage`: Splits by double line breaks ("\\n\\n")
- `page`: Splits by form feed characters ("\\f")
- `line`: Splits by single line breaks ("\\n")
- `period`: Splits by periods (".")
- `function`: Uses a custom splitting function
Each extracted chunk retains metadata from the original document and includes additional fields:
- `source_id`: The ID of the original document
- `page_number`: The page number the chunk belongs to
- `split_id`: The sequential ID of the split within the document
- `split_idx_start`: The starting index of the chunk in the original document
When `respect_sentence_boundary=True` is set, the component uses HanLP's sentence tokenizer (`UD_CTB_EOS_MUL`) to ensure that splits occur only between complete sentences, preserving the semantic integrity of the text.
## Usage
### On its own
You can use `ChineseDocumentSplitter` outside of a pipeline to process Chinese documents directly:
```python
from haystack import Document
from haystack_integrations.components.preprocessors.hanlp import ChineseDocumentSplitter
# Initialize the splitter with word-based splitting
splitter = ChineseDocumentSplitter(
split_by="word",
split_length=10,
split_overlap=3,
granularity="coarse",
)
# Create a Chinese document
doc = Document(
content="这是第一句话,这是第二句话,这是第三句话。这是第四句话,这是第五句话,这是第六句话!",
)
# Split the document
result = splitter.run(documents=[doc])
print(result["documents"]) # List of split documents
```
### With sentence boundary respect
When splitting by words, you can ensure that sentence boundaries are respected:
```python
from haystack import Document
from haystack_integrations.components.preprocessors.hanlp import ChineseDocumentSplitter
doc = Document(
content="这是第一句话,这是第二句话,这是第三句话。"
"这是第四句话,这是第五句话,这是第六句话!"
"这是第七句话,这是第八句话,这是第九句话?",
)
splitter = ChineseDocumentSplitter(
split_by="word",
split_length=10,
split_overlap=3,
respect_sentence_boundary=True,
granularity="coarse",
)
result = splitter.run(documents=[doc])
# Each chunk will end with a complete sentence
for doc in result["documents"]:
print(f"Chunk: {doc.content}")
print(f"Ends with sentence: {doc.content.endswith(('。', '', ''))}")
```
### With fine granularity
For more detailed word segmentation:
```python
from haystack import Document
from haystack_integrations.components.preprocessors.hanlp import ChineseDocumentSplitter
doc = Document(content="人工智能技术正在快速发展,改变着我们的生活方式。")
splitter = ChineseDocumentSplitter(
split_by="word",
split_length=5,
split_overlap=0,
granularity="fine", # More detailed segmentation
)
result = splitter.run(documents=[doc])
print(result["documents"])
```
### With custom splitting function
You can also use a custom function for splitting:
```python
from haystack import Document
from haystack_integrations.components.preprocessors.hanlp import ChineseDocumentSplitter
def custom_split(text: str) -> list[str]:
"""Custom splitting function that splits by commas"""
return text.split("")
doc = Document(content="第一段,第二段,第三段,第四段")
splitter = ChineseDocumentSplitter(split_by="function", splitting_function=custom_split)
splitter.warm_up()
result = splitter.run(documents=[doc])
print(result["documents"])
```
### In a pipeline
Here's how you can integrate `ChineseDocumentSplitter` into a Haystack indexing pipeline:
```python
from haystack import Pipeline, Document
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters.txt import TextFileToDocument
from haystack_integrations.components.preprocessors.hanlp import ChineseDocumentSplitter
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.writers import DocumentWriter
# Initialize components
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component(instance=TextFileToDocument(), name="text_file_converter")
p.add_component(instance=DocumentCleaner(), name="cleaner")
p.add_component(
instance=ChineseDocumentSplitter(
split_by="word",
split_length=100,
split_overlap=20,
respect_sentence_boundary=True,
granularity="coarse",
),
name="chinese_splitter",
)
p.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
# Connect components
p.connect("text_file_converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "chinese_splitter.documents")
p.connect("chinese_splitter.documents", "writer.documents")
# Run pipeline with Chinese text files
p.run({"text_file_converter": {"sources": ["path/to/your/chinese/files.txt"]}})
```
This pipeline processes Chinese text files by converting them to documents, cleaning the text, splitting them into linguistically-aware chunks using Chinese word segmentation, and storing the results in the Document Store for further retrieval and processing.
@@ -0,0 +1,129 @@
---
title: "ChonkieRecursiveDocumentSplitter"
id: chonkierecursivedocumentsplitter
slug: "/chonkierecursivedocumentsplitter"
description: "Use `ChonkieRecursiveDocumentSplitter` to split documents recursively using a hierarchy of rules, powered by the Chonkie library."
---
# ChonkieRecursiveDocumentSplitter
`ChonkieRecursiveDocumentSplitter` splits documents using a hierarchy of splitting rules via [Chonkie](https://docs.chonkie.ai/)'s `RecursiveChunker`.
It applies progressively finer-grained splits until all chunks satisfy the configured size constraints, making it effective for structured text like Markdown or code.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx), before [Embedders](../embedders.mdx) |
| **Mandatory run variables** | `documents`: A list of documents |
| **Output variables** | `documents`: A list of documents |
| **API reference** | [Chonkie](/reference/integrations-chonkie) |
| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chonkie |
</div>
## Overview
`ChonkieRecursiveDocumentSplitter` wraps Chonkie's `RecursiveChunker` to split documents by applying splitting rules level by level.
If a chunk produced at one level still exceeds `chunk_size`, the next level's rules are applied to it.
This continues recursively until all chunks are within the size limit.
You can customize the splitting behavior by providing `RecursiveRules` from Chonkie.
See the [Chonkie documentation](https://docs.chonkie.ai/) for details on defining custom rules.
Each output document includes the original document's metadata plus:
- `source_id`: ID of the original document
- `page_number`: Page number of the chunk within the original document
- `split_id`: Index of the chunk within the document
- `split_idx_start` / `split_idx_end`: Character offsets of the chunk in the original text
- `token_count`: Number of tokens in the chunk
## Installation
```bash
pip install chonkie-haystack
```
## Configuration
| Parameter | Default | Description |
| --- | --- | --- |
| `tokenizer` | `"character"` | Tokenizer to use. Common options: `"character"`, `"gpt2"`, `"cl100k_base"`. See [Chonkie docs](https://docs.chonkie.ai/) for all options. |
| `chunk_size` | `2048` | Maximum number of tokens per chunk. |
| `min_characters_per_chunk` | `24` | Minimum number of characters a chunk must contain. |
| `rules` | `None` | Custom `RecursiveRules` defining the splitting hierarchy. If `None`, Chonkie's default rules are used. |
| `skip_empty_documents` | `True` | Whether to skip documents with empty content. |
| `page_break_character` | `"\f"` | Character used to detect page breaks when tracking page numbers. |
## Usage
### On its own
```python
from haystack import Document
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieRecursiveDocumentSplitter,
)
chunker = ChonkieRecursiveDocumentSplitter(chunk_size=512)
documents = [
Document(
content="# Introduction\n\nHaystack is a framework.\n\n## Features\n\nIt supports RAG pipelines.",
),
]
result = chunker.run(documents=documents)
print(result["documents"])
```
### With custom rules
```python
from chonkie.types.recursive import RecursiveLevel, RecursiveRules
from haystack import Document
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieRecursiveDocumentSplitter,
)
rules = RecursiveRules(
levels=[
RecursiveLevel(delimiters=["\n\n"]),
RecursiveLevel(delimiters=["\n"]),
RecursiveLevel(delimiters=[". ", "! ", "? "]),
],
)
chunker = ChonkieRecursiveDocumentSplitter(chunk_size=256, rules=rules)
documents = [Document(content="First paragraph.\n\nSecond paragraph with more detail.")]
result = chunker.run(documents=documents)
print(result["documents"])
```
### In a pipeline
```python
from pathlib import Path
from haystack import Pipeline
from haystack.components.converters import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieRecursiveDocumentSplitter,
)
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component("converter", TextFileToDocument())
p.add_component("cleaner", DocumentCleaner())
p.add_component("splitter", ChonkieRecursiveDocumentSplitter(chunk_size=512))
p.add_component("writer", DocumentWriter(document_store=document_store))
p.connect("converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
files = list(Path("path/to/your/files").glob("*.md"))
p.run({"converter": {"sources": files}})
```
@@ -0,0 +1,119 @@
---
title: "ChonkieSemanticDocumentSplitter"
id: chonkiesemanticdocumentsplitter
slug: "/chonkiesemanticdocumentsplitter"
description: "Use `ChonkieSemanticDocumentSplitter` to split documents at semantic topic boundaries using embedding similarity, powered by the Chonkie library."
---
# ChonkieSemanticDocumentSplitter
`ChonkieSemanticDocumentSplitter` splits documents at semantically meaningful boundaries using [Chonkie](https://docs.chonkie.ai/)'s `SemanticChunker`.
Rather than splitting by a fixed token count, it uses an embedding model to detect topic shifts and keeps related sentences together.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx), before [Embedders](../embedders.mdx) |
| **Mandatory run variables** | `documents`: A list of documents |
| **Output variables** | `documents`: A list of documents |
| **API reference** | [Chonkie](/reference/integrations-chonkie) |
| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chonkie |
</div>
## Overview
`ChonkieSemanticDocumentSplitter` wraps Chonkie's `SemanticChunker` to produce context-aware chunks by grouping sentences with similar semantic content.
It computes embeddings for sentences and uses cosine similarity to find natural topic boundaries.
The embedding model is loaded lazily — `warm_up()` is called automatically the first time `run()` is invoked, whether inside a pipeline or standalone.
Each output document includes the original document's metadata plus:
- `source_id`: ID of the original document
- `page_number`: Page number of the chunk within the original document
- `split_id`: Index of the chunk within the document
- `split_idx_start` / `split_idx_end`: Character offsets of the chunk in the original text
- `token_count`: Number of tokens in the chunk
## Installation
```bash
pip install chonkie-haystack
```
## Configuration
| Parameter | Default | Description |
| --- | --- | --- |
| `embedding_model` | `"minishlab/potion-base-32M"` | The embedding model used to compute sentence similarity. See [Chonkie docs](https://docs.chonkie.ai/) for supported models. |
| `threshold` | `0.8` | Cosine similarity threshold below which a sentence boundary becomes a split point. |
| `chunk_size` | `2048` | Maximum number of tokens per chunk (based on the embedding model's tokenizer). |
| `similarity_window` | `3` | Number of surrounding sentences to include when computing similarity. |
| `min_sentences_per_chunk` | `1` | Minimum number of sentences that must be included in each chunk. |
| `min_characters_per_sentence` | `24` | Minimum number of characters for a sentence to be considered valid. |
| `delim` | `None` | Custom sentence delimiters. If `None`, Chonkie's default delimiters are used. |
| `include_delim` | `"prev"` | Whether to attach the delimiter to the previous (`"prev"`) or next (`"next"`) chunk. |
| `skip_window` | `0` | Number of sentences to skip when computing similarity scores. |
| `filter_window` | `5` | Window size for the Savitzky-Golay smoothing filter applied to similarity scores. |
| `filter_polyorder` | `3` | Polynomial order for the Savitzky-Golay filter. |
| `filter_tolerance` | `0.2` | Tolerance used when filtering similarity scores. |
| `skip_empty_documents` | `True` | Whether to skip documents with empty content. |
| `page_break_character` | `"\f"` | Character used to detect page breaks when tracking page numbers. |
## Usage
### On its own
```python
from haystack import Document
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieSemanticDocumentSplitter,
)
chunker = ChonkieSemanticDocumentSplitter(chunk_size=512, threshold=0.5)
documents = [
Document(
content="Haystack is an open-source framework for LLM applications. "
"It makes building RAG pipelines easy. "
"The Eiffel Tower is located in Paris. "
"Paris is the capital of France.",
),
]
result = chunker.run(documents=documents)
print(result["documents"])
```
### In a pipeline
```python
from pathlib import Path
from haystack import Pipeline
from haystack.components.converters import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieSemanticDocumentSplitter,
)
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component("converter", TextFileToDocument())
p.add_component("cleaner", DocumentCleaner())
p.add_component(
"splitter",
ChonkieSemanticDocumentSplitter(chunk_size=512, threshold=0.5),
)
p.add_component("writer", DocumentWriter(document_store=document_store))
p.connect("converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
files = list(Path("path/to/your/files").glob("*.txt"))
p.run({"converter": {"sources": files}})
```
@@ -0,0 +1,113 @@
---
title: "ChonkieSentenceDocumentSplitter"
id: chonkiesentencedocumentsplitter
slug: "/chonkiesentencedocumentsplitter"
description: "Use `ChonkieSentenceDocumentSplitter` to split documents into sentence-aware chunks using the Chonkie library."
---
# ChonkieSentenceDocumentSplitter
`ChonkieSentenceDocumentSplitter` splits documents into chunks that respect sentence boundaries using [Chonkie](https://docs.chonkie.ai/)'s `SentenceChunker`.
Unlike pure token splitting, it avoids cutting mid-sentence, producing more coherent chunks.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) and [`DocumentCleaner`](documentcleaner.mdx), before [Embedders](../embedders.mdx) |
| **Mandatory run variables** | `documents`: A list of documents |
| **Output variables** | `documents`: A list of documents |
| **API reference** | [Chonkie](/reference/integrations-chonkie) |
| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chonkie |
</div>
## Overview
`ChonkieSentenceDocumentSplitter` wraps Chonkie's `SentenceChunker` to split each input document into chunks whose boundaries align with sentence endings.
The chunker groups sentences together until the chunk size limit is reached.
Each output document includes the original document's metadata plus:
- `source_id`: ID of the original document
- `page_number`: Page number of the chunk within the original document
- `split_id`: Index of the chunk within the document
- `split_idx_start` / `split_idx_end`: Character offsets of the chunk in the original text
- `token_count`: Number of tokens in the chunk
## Installation
```bash
pip install chonkie-haystack
```
## Configuration
| Parameter | Default | Description |
| --- | --- | --- |
| `tokenizer` | `"character"` | Tokenizer to use. Common options: `"character"`, `"gpt2"`, `"cl100k_base"`. See [Chonkie docs](https://docs.chonkie.ai/) for all options. |
| `chunk_size` | `2048` | Maximum number of tokens per chunk. |
| `chunk_overlap` | `0` | Number of overlapping tokens between consecutive chunks. |
| `min_sentences_per_chunk` | `1` | Minimum number of sentences that must be included in each chunk. |
| `min_characters_per_sentence` | `12` | Minimum number of characters for a sentence to be considered valid. |
| `approximate` | `False` | Whether to use approximate chunking for faster processing. |
| `delim` | `None` | Custom sentence delimiters. If `None`, Chonkie's default delimiters are used. |
| `include_delim` | `"prev"` | Whether to attach the delimiter to the previous (`"prev"`) or next (`"next"`) chunk. |
| `skip_empty_documents` | `True` | Whether to skip documents with empty content. |
| `page_break_character` | `"\f"` | Character used to detect page breaks when tracking page numbers. |
## Usage
### On its own
```python
from haystack import Document
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieSentenceDocumentSplitter,
)
chunker = ChonkieSentenceDocumentSplitter(
tokenizer="gpt2",
chunk_size=512,
chunk_overlap=0,
)
documents = [
Document(
content="Haystack is an open-source framework. It helps you build LLM applications.",
),
]
result = chunker.run(documents=documents)
print(result["documents"])
```
### In a pipeline
```python
from pathlib import Path
from haystack import Pipeline
from haystack.components.converters import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieSentenceDocumentSplitter,
)
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component("converter", TextFileToDocument())
p.add_component("cleaner", DocumentCleaner())
p.add_component(
"splitter",
ChonkieSentenceDocumentSplitter(tokenizer="gpt2", chunk_size=512),
)
p.add_component("writer", DocumentWriter(document_store=document_store))
p.connect("converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
files = list(Path("path/to/your/files").glob("*.txt"))
p.run({"converter": {"sources": files}})
```
@@ -0,0 +1,108 @@
---
title: "ChonkieTokenDocumentSplitter"
id: chonkietokendocumentsplitter
slug: "/chonkietokendocumentsplitter"
description: "Use `ChonkieTokenDocumentSplitter` to split documents into token-based chunks using the Chonkie library."
---
# ChonkieTokenDocumentSplitter
`ChonkieTokenDocumentSplitter` splits documents into fixed-size token-based chunks using [Chonkie](https://docs.chonkie.ai/)'s `TokenChunker`.
It supports multiple tokenizers and is well-suited for splitting long documents before indexing.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) and [`DocumentCleaner`](documentcleaner.mdx), before [Embedders](../embedders.mdx) |
| **Mandatory run variables** | `documents`: A list of documents |
| **Output variables** | `documents`: A list of documents |
| **API reference** | [Chonkie](/reference/integrations-chonkie) |
| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chonkie |
</div>
## Overview
`ChonkieTokenDocumentSplitter` wraps Chonkie's `TokenChunker` to split each input document into smaller chunks based on token count.
You can configure the tokenizer, chunk size, and overlap between chunks.
Each output document includes the original document's metadata plus:
- `source_id`: ID of the original document
- `page_number`: Page number of the chunk within the original document
- `split_id`: Index of the chunk within the document
- `split_idx_start` / `split_idx_end`: Character offsets of the chunk in the original text
- `token_count`: Number of tokens in the chunk
## Installation
```bash
pip install chonkie-haystack
```
## Configuration
| Parameter | Default | Description |
| --- | --- | --- |
| `tokenizer` | `"character"` | Tokenizer to use. Common options: `"character"`, `"gpt2"`, `"cl100k_base"`. See [Chonkie docs](https://docs.chonkie.ai/) for all options. |
| `chunk_size` | `2048` | Maximum number of tokens per chunk. |
| `chunk_overlap` | `0` | Number of overlapping tokens between consecutive chunks. |
| `skip_empty_documents` | `True` | Whether to skip documents with empty content. |
| `page_break_character` | `"\f"` | Character used to detect page breaks when tracking page numbers. |
## Usage
### On its own
```python
from haystack import Document
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieTokenDocumentSplitter,
)
chunker = ChonkieTokenDocumentSplitter(
tokenizer="gpt2",
chunk_size=512,
chunk_overlap=50,
)
documents = [
Document(
content="Haystack is an open-source framework for building LLM applications.",
),
]
result = chunker.run(documents=documents)
print(result["documents"])
```
### In a pipeline
```python
from pathlib import Path
from haystack import Pipeline
from haystack.components.converters import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.preprocessors.chonkie import (
ChonkieTokenDocumentSplitter,
)
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component("converter", TextFileToDocument())
p.add_component("cleaner", DocumentCleaner())
p.add_component(
"splitter",
ChonkieTokenDocumentSplitter(tokenizer="gpt2", chunk_size=512),
)
p.add_component("writer", DocumentWriter(document_store=document_store))
p.connect("converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
files = list(Path("path/to/your/files").glob("*.txt"))
p.run({"converter": {"sources": files}})
```
@@ -0,0 +1,90 @@
---
title: "CSVDocumentCleaner"
id: csvdocumentcleaner
slug: "/csvdocumentcleaner"
description: "Use `CSVDocumentCleaner` to clean CSV documents by removing empty rows and columns while preserving specific ignored rows and columns. It processes CSV content stored in documents and helps standardize data for further analysis."
---
# CSVDocumentCleaner
Use `CSVDocumentCleaner` to clean CSV documents by removing empty rows and columns while preserving specific ignored rows and columns. It processes CSV content stored in documents and helps standardize data for further analysis.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) , before [Embedders](../embedders.mdx) or [Writers](../writers/documentwriter.mdx) |
| **Mandatory run variables** | `documents`: A list of documents containing CSV content |
| **Output variables** | `documents`: A list of cleaned CSV documents |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/csv_document_cleaner.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
`CSVDocumentCleaner` expects a list of `Document` objects as input, each containing CSV-formatted content as text. It cleans the data by removing fully empty rows and columns while allowing users to specify the number of rows and columns to be preserved before cleaning.
### Parameters
- `ignore_rows`: Number of rows to ignore from the top of the CSV table before processing. If any columns are removed, the same columns will be dropped from the ignored rows.
- `ignore_columns`: Number of columns to ignore from the left of the CSV table before processing. If any rows are removed, the same rows will be dropped from the ignored columns.
- `remove_empty_rows`: Whether to remove entirely empty rows.
- `remove_empty_columns`: Whether to remove entirely empty columns.
- `keep_id`: Whether to retain the original document ID in the output document.
### Cleaning Process
The `CSVDocumentCleaner` algorithm follows these steps:
1. Reads each document's content as a CSV table using pandas.
2. Retains the specified number of `ignore_rows` from the top and `ignore_columns` from the left.
3. Drops any rows and columns that are entirely empty (contain only NaN values).
4. If columns are dropped, they are also removed from ignored rows.
5. If rows are dropped, they are also removed from ignored columns.
6. Reattaches the remaining ignored rows and columns to maintain their original positions.
7. Returns the cleaned CSV content as a new `Document` object.
## Usage
### On its own
You can use `CSVDocumentCleaner` independently to clean up CSV documents:
```python
from haystack import Document
from haystack.components.preprocessors import CSVDocumentCleaner
cleaner = CSVDocumentCleaner(ignore_rows=1, ignore_columns=0)
documents = [Document(content="""col1,col2,col3\n,,\na,b,c\n,,""")]
cleaned_docs = cleaner.run(documents=documents)
```
### In a pipeline
```python
from pathlib import Path
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters import XLSXToDocument
from haystack.components.preprocessors import CSVDocumentCleaner
from haystack.components.writers import DocumentWriter
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component(instance=XLSXToDocument(), name="xlsx_file_converter")
p.add_component(
instance=CSVDocumentCleaner(ignore_rows=1, ignore_columns=1),
name="csv_cleaner",
)
p.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
p.connect("xlsx_file_converter.documents", "csv_cleaner.documents")
p.connect("csv_cleaner.documents", "writer.documents")
p.run({"xlsx_file_converter": {"sources": [Path("your_xlsx_file.xlsx")]}})
```
This ensures that CSV documents are properly cleaned before further processing or storage.
@@ -0,0 +1,118 @@
---
title: "CSVDocumentSplitter"
id: csvdocumentsplitter
slug: "/csvdocumentsplitter"
description: "`CSVDocumentSplitter` divides CSV documents into smaller sub-tables based on split arguments. This is useful for handling structured data that contains multiple tables, improving data processing efficiency and retrieval."
---
# CSVDocumentSplitter
`CSVDocumentSplitter` divides CSV documents into smaller sub-tables based on split arguments. This is useful for handling structured data that contains multiple tables, improving data processing efficiency and retrieval.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) , before [CSVDocumentCleaner](csvdocumentcleaner.mdx) |
| **Mandatory run variables** | `documents`: A list of documents with CSV-formatted content |
| **Output variables** | `documents`: A list of documents, each containing a sub-table extracted from the original CSV file |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/csv_document_splitter.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
`CSVDocumentSplitter` expects a list of documents containing CSV-formatted content and returns a list of new `Document` objects, each representing a sub-table extracted from the original document.
There are two modes of operation for the splitter:
1. `threshold` (Default): Identifies empty rows or columns exceeding a given threshold and splits the document accordingly.
2. `row-wise`: Splits each row into a separate document, treating each as an independent sub-table.
The splitting process follows these rules:
1. **Row-Based Splitting**: If `row_split_threshold` is set, consecutive empty rows equalling or exceeding this threshold trigger a split.
2. **Column-Based Splitting**: If `column_split_threshold` is set, consecutive empty columns equalling or exceeding this threshold trigger a split.
3. **Recursive Splitting**: If both thresholds are provided, `CSVDocumentSplitter` first splits by rows and then by columns. If more empty rows are detected, the splitting process is called again. This ensures that sub-tables are fully separated.
Each extracted sub-table retains metadata from the original document and includes additional fields:
- `source_id`: The ID of the original document
- `row_idx_start`: The starting row index of the sub-table in the original document
- `col_idx_start`: The starting column index of the sub-table in the original document
- `split_id`: The sequential ID of the split within the document
This component is especially useful for document processing pipelines that require structured data to be extracted and stored efficiently.
### Supported Document Stores
`CSVDocumentSplitter` is compatible with the following Document Stores:
- [AstraDocumentStore](../../document-stores/astradocumentstore.mdx)
- [ChromaDocumentStore](../../document-stores/chromadocumentstore.mdx)
- [ElasticsearchDocumentStore](../../document-stores/elasticsearch-document-store.mdx)
- [OpenSearchDocumentStore](../../document-stores/opensearch-document-store.mdx)
- [PgvectorDocumentStore](../../document-stores/pgvectordocumentstore.mdx)
- [PineconeDocumentStore](../../document-stores/pinecone-document-store.mdx)
- [QdrantDocumentStore](../../document-stores/qdrant-document-store.mdx)
- [WeaviateDocumentStore](../../document-stores/weaviatedocumentstore.mdx)
- [MilvusDocumentStore](https://haystack.deepset.ai/integrations/milvus-document-store)
- [Neo4jDocumentStore](https://haystack.deepset.ai/integrations/neo4j-document-store)
## Usage
### On its own
You can use `CSVDocumentSplitter` outside of a pipeline to process CSV documents directly:
```python
from haystack import Document
from haystack.components.preprocessors import CSVDocumentSplitter
splitter = CSVDocumentSplitter(row_split_threshold=1, column_split_threshold=1)
doc = Document(
content="""ID,LeftVal,,,RightVal,Extra
1,Hello,,,World,Joined
2,StillLeft,,,StillRight,Bridge
,,,,,
A,B,,,C,D
E,F,,,G,H
""",
)
split_result = splitter.run([doc])
print(split_result["documents"]) # List of split tables as Documents
```
### In a pipeline
Here's how you can integrate `CSVDocumentSplitter` into a Haystack indexing pipeline:
```python
from haystack import Pipeline, Document
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters.csv import CSVToDocument
from haystack.components.preprocessors import CSVDocumentSplitter
from haystack.components.preprocessors import CSVDocumentCleaner
from haystack.components.writers import DocumentWriter
# Initialize components
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component(instance=CSVToDocument(), name="csv_file_converter")
p.add_component(instance=CSVDocumentSplitter(), name="splitter")
p.add_component(instance=CSVDocumentCleaner(), name="cleaner")
p.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
# Connect components
p.connect("csv_file_converter.documents", "splitter.documents")
p.connect("splitter.documents", "cleaner.documents")
p.connect("cleaner.documents", "writer.documents")
# Run pipeline
p.run({"csv_file_converter": {"sources": ["path/to/your/file.csv"]}})
```
This pipeline extracts CSV content, splits it into structured sub-tables, cleans the CSV documents by removing empty rows and columns, and stores the resulting documents in the Document Store for further retrieval and processing.
@@ -0,0 +1,152 @@
---
title: "DocumentCleaner"
id: documentcleaner
slug: "/documentcleaner"
description: "Use `DocumentCleaner` to make text documents more readable. It removes extra whitespaces, empty lines, specified substrings, regexes, page headers, and footers in this particular order. This is useful for preparing the documents for further processing by LLMs."
---
# DocumentCleaner
Use `DocumentCleaner` to make text documents more readable. It removes extra whitespaces, empty lines, specified substrings, regexes, page headers, and footers in this particular order. This is useful for preparing the documents for further processing by LLMs.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) , after [`DocumentSplitter`](documentsplitter.mdx) |
| **Mandatory run variables** | `documents`: A list of documents |
| **Output variables** | `documents`: A list of documents |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/document_cleaner.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
`DocumentCleaner` expects a list of documents as input and returns a list of documents with cleaned texts. Selectable cleaning steps for each input document are to `remove_empty_lines`, `remove_extra_whitespaces` and to `remove_repeated_substrings`. These three parameters are booleans that can be set when the component is initialized.
- `unicode_normalization` normalizes Unicode characters to a standard form. The parameter can be set to NFC, NFKC, NFD, or NFKD.
- `ascii_only` removes accents from characters and replaces them with their closest ASCII equivalents.
- `remove_empty_lines` removes empty lines from the document.
- `remove_extra_whitespaces` removes extra whitespaces from the document.
- `remove_repeated_substrings` removes repeated substrings (headers/footers) from pages in the document. Pages in the text need to be separated by form feed character "\\f", which is supported by [`TextFileToDocument`](../converters/textfiletodocument.mdx), [`AzureOCRDocumentConverter`](../converters/azureocrdocumentconverter.mdx), [`MistralOCRDocumentConverter`](../converters/mistralocrdocumentconverter.mdx), and [`PaddleOCRVLDocumentConverter`](../converters/paddleocrvldocumentconverter.mdx).
:::note
`remove_extra_whitespaces` and `remove_empty_lines` work best on plain-text content. If your converter returns Markdown, such as [`AzureDocumentIntelligenceConverter`](../converters/azuredocumentintelligenceconverter.mdx), [`MarkItDownConverter`](../converters/markitdownconverter.mdx), [`MistralOCRDocumentConverter`](../converters/mistralocrdocumentconverter.mdx), or [`PaddleOCRVLDocumentConverter`](../converters/paddleocrvldocumentconverter.mdx), disable those options to preserve headings, tables, lists, and image tags.
:::
In addition, you can specify a list of strings that should be removed from all documents as part of the cleaning with the parameter `remove_substring`. You can also specify a regular expression with the parameter `remove_regex` and any matches will be removed.
The cleaning steps are executed in the following order:
1. unicode_normalization
2. ascii_only
3. remove_extra_whitespaces
4. remove_empty_lines
5. remove_substrings
6. remove_regex
7. remove_repeated_substrings
## Usage
### On its own
You can use it outside of a pipeline to clean up your documents:
```python
from haystack import Document
from haystack.components.preprocessors import DocumentCleaner
doc = Document(content="This is a document to clean\n\n\nsubstring to remove")
cleaner = DocumentCleaner(remove_substrings=["substring to remove"])
result = cleaner.run(documents=[doc])
assert result["documents"][0].content == "This is a document to clean "
```
### In a pipeline
```python
from haystack import Document
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.preprocessors import DocumentSplitter
from haystack.components.writers import DocumentWriter
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component(instance=TextFileToDocument(), name="text_file_converter")
p.add_component(instance=DocumentCleaner(), name="cleaner")
p.add_component(
instance=DocumentSplitter(split_by="sentence", split_length=1),
name="splitter",
)
p.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
p.connect("text_file_converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
p.run({"text_file_converter": {"sources": your_files}})
```
### In YAML
```yaml
components:
cleaner:
init_parameters:
ascii_only: false
keep_id: false
remove_empty_lines: true
remove_extra_whitespaces: true
remove_regex: null
remove_repeated_substrings: false
remove_substrings: null
replace_regexes: null
strip_whitespaces: false
unicode_normalization: null
type: haystack.components.preprocessors.document_cleaner.DocumentCleaner
splitter:
init_parameters:
extend_abbreviations: true
language: en
respect_sentence_boundary: false
skip_empty_documents: true
split_by: sentence
split_length: 1
split_overlap: 0
split_threshold: 0
use_split_rules: true
type: haystack.components.preprocessors.document_splitter.DocumentSplitter
text_file_converter:
init_parameters:
encoding: utf-8
store_full_path: false
type: haystack.components.converters.txt.TextFileToDocument
writer:
init_parameters:
document_store:
init_parameters:
bm25_algorithm: BM25L
bm25_parameters: {}
bm25_tokenization_regex: (?u)\\b\\w+\\b
embedding_similarity_function: dot_product
index: 64e4f9ab-87fb-47fd-b390-dabcfda61447
return_embedding: true
type: haystack.document_stores.in_memory.document_store.InMemoryDocumentStore
policy: NONE
type: haystack.components.writers.document_writer.DocumentWriter
connection_type_validation: true
connections:
- receiver: cleaner.documents
sender: text_file_converter.documents
- receiver: splitter.documents
sender: cleaner.documents
- receiver: writer.documents
sender: splitter.documents
max_runs_per_component: 100
metadata: {}
```
@@ -0,0 +1,80 @@
---
title: "DocumentPreprocessor"
id: documentpreprocessor
slug: "/documentpreprocessor"
description: "Divides a list of text documents into a list of shorter text documents and then makes them more readable by cleaning."
---
# DocumentPreprocessor
Divides a list of text documents into a list of shorter text documents and then makes them more readable by cleaning.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx)  |
| **Mandatory run variables** | `documents`: A list of documents |
| **Output variables** | `documents`: A list of split and cleaned documents |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/document_preprocessor.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
`DocumentPreprocessor` first splits and then cleans documents.
It is a SuperComponent that combines a `DocumentSplitter` and a `DocumentCleaner` into a single component.
### Parameters
The `DocumentPreprocessor` exposes all initialization parameters of the underlying `DocumentSplitter` and `DocumentCleaner`, and they are all optional. A detailed description of their parameters is in the respective documentation pages:
- [DocumentSplitter](documentsplitter.mdx)
- [DocumentCleaner](documentcleaner.mdx)
## Usage
### On its own
```python
from haystack import Document
from haystack.components.preprocessors import DocumentPreprocessor
doc = Document(content="I love pizza!")
preprocessor = DocumentPreprocessor()
result = preprocessor.run(documents=[doc])
print(result["documents"])
```
### In a pipeline
You can use the `DocumentPreprocessor` in your indexing pipeline. The example below requires installing additional dependencies for the `MultiFileConverter`:
```shell
pip install pypdf markdown-it-py mdit_plain trafilatura python-pptx python-docx jq openpyxl tabulate pandas
```
```python
from haystack import Pipeline
from haystack.components.converters import MultiFileConverter
from haystack.components.preprocessors import DocumentPreprocessor
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
document_store = InMemoryDocumentStore()
pipeline = Pipeline()
pipeline.add_component("converter", MultiFileConverter())
pipeline.add_component("preprocessor", DocumentPreprocessor())
pipeline.add_component("writer", DocumentWriter(document_store=document_store))
pipeline.connect("converter", "preprocessor")
pipeline.connect("preprocessor", "writer")
result = pipeline.run(data={"sources": ["test.txt", "test.pdf"]})
print(result)
# {'writer': {'documents_written': 3}}
```
@@ -0,0 +1,159 @@
---
title: "DocumentSplitter"
id: documentsplitter
slug: "/documentsplitter"
description: "`DocumentSplitter` divides a list of text documents into a list of shorter text documents. This is useful for long texts that otherwise wouldn't fit into the maximum text length of language models and can also speed up question answering."
---
# DocumentSplitter
`DocumentSplitter` divides a list of text documents into a list of shorter text documents. This is useful for long texts that otherwise wouldn't fit into the maximum text length of language models and can also speed up question answering.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) and [`DocumentCleaner`](documentcleaner.mdx) , before [Classifiers](../classifiers.mdx) |
| **Mandatory run variables** | `documents`: A list of documents |
| **Output variables** | `documents`: A list of documents |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/document_splitter.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
`DocumentSplitter` expects a list of documents as input and returns a list of documents with split texts. It splits each input document by `split_by` after `split_length` units with an overlap of `split_overlap` units. These additional parameters can be set when the component is initialized:
- `split_by` can be `"word"`, `"sentence"`, `"passage"` (paragraph), `"page"`, `"line"` or `"function"`.
- `split_length` is an integer indicating the chunk size, which is the number of words, sentences, or passages.
- `split_overlap` is an integer indicating the number of overlapping words, sentences, or passages between chunks.
- `split_threshold` is an integer indicating the minimum number of words, sentences, or passages that the document fragment should have. If the fragment is below the threshold, it will be attached to the previous one.
A field `"source_id"` is added to each document's `meta` data to keep track of the original document that was split. Another meta field `"page_number"` is added to each document to keep track of the page it belonged to in the original document. Other metadata are copied from the original document.
The DocumentSplitter is compatible with the following DocumentStores:
- [AstraDocumentStore](../../document-stores/astradocumentstore.mdx)
- [ChromaDocumentStore](../../document-stores/chromadocumentstore.mdx) limited support, overlapping information is not stored.
- [ElasticsearchDocumentStore](../../document-stores/elasticsearch-document-store.mdx)
- [OpenSearchDocumentStore](../../document-stores/opensearch-document-store.mdx)
- [PgvectorDocumentStore](../../document-stores/pgvectordocumentstore.mdx)
- [PineconeDocumentStore](../../document-stores/pinecone-document-store.mdx) limited support, overlapping information is not stored.
- [QdrantDocumentStore](../../document-stores/qdrant-document-store.mdx)
- [WeaviateDocumentStore](../../document-stores/weaviatedocumentstore.mdx)
- [MilvusDocumentStore](https://haystack.deepset.ai/integrations/milvus-document-store)
- [Neo4jDocumentStore](https://haystack.deepset.ai/integrations/neo4j-document-store)
## Usage
### On its own
You can use this component outside of a pipeline to shorten your documents like this:
```python
from haystack import Document
from haystack.components.preprocessors import DocumentSplitter
doc = Document(
content="Moonlight shimmered softly, wolves howled nearby, night enveloped everything.",
)
splitter = DocumentSplitter(split_by="word", split_length=3, split_overlap=0)
result = splitter.run(documents=[doc])
```
### In a pipeline
Here's how you can use `DocumentSplitter` in an indexing pipeline:
```python
from pathlib import Path
from haystack import Document
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters.txt import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.preprocessors import DocumentSplitter
from haystack.components.writers import DocumentWriter
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component(instance=TextFileToDocument(), name="text_file_converter")
p.add_component(instance=DocumentCleaner(), name="cleaner")
p.add_component(
instance=DocumentSplitter(split_by="sentence", split_length=1),
name="splitter",
)
p.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
p.connect("text_file_converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
path = "path/to/your/files"
files = list(Path(path).glob("*.md"))
p.run({"text_file_converter": {"sources": files}})
```
### In YAML
This is the YAML representation of the indexing pipeline shown above. It reads text files, cleans the text, splits it into individual sentences, and writes them to an in-memory document store.
```yaml
components:
cleaner:
init_parameters:
ascii_only: false
keep_id: false
remove_empty_lines: true
remove_extra_whitespaces: true
remove_regex: null
remove_repeated_substrings: false
remove_substrings: null
replace_regexes: null
strip_whitespaces: false
unicode_normalization: null
type: haystack.components.preprocessors.document_cleaner.DocumentCleaner
splitter:
init_parameters:
extend_abbreviations: true
language: en
respect_sentence_boundary: false
skip_empty_documents: true
split_by: sentence
split_length: 1
split_overlap: 0
split_threshold: 0
use_split_rules: true
type: haystack.components.preprocessors.document_splitter.DocumentSplitter
text_file_converter:
init_parameters:
encoding: utf-8
store_full_path: false
type: haystack.components.converters.txt.TextFileToDocument
writer:
init_parameters:
document_store:
init_parameters:
bm25_algorithm: BM25L
bm25_parameters: {}
bm25_tokenization_regex: (?u)\\b\\w+\\b
embedding_similarity_function: dot_product
index: 64e4f9ab-87fb-47fd-b390-dabcfda61447
return_embedding: true
type: haystack.document_stores.in_memory.document_store.InMemoryDocumentStore
policy: NONE
type: haystack.components.writers.document_writer.DocumentWriter
connection_type_validation: true
connections:
- receiver: cleaner.documents
sender: text_file_converter.documents
- receiver: splitter.documents
sender: cleaner.documents
- receiver: writer.documents
sender: splitter.documents
max_runs_per_component: 100
metadata: {}
```
@@ -0,0 +1,98 @@
---
title: "EmbeddingBasedDocumentSplitter"
id: embeddingbaseddocumentsplitter
slug: "/embeddingbaseddocumentsplitter"
description: "Use this component to split documents based on embedding similarity using cosine distances between sequential sentence groups."
---
# EmbeddingBasedDocumentSplitter
Use this component to split documents based on embedding similarity using cosine distances between sequential sentence groups.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) and [`DocumentCleaner`](documentcleaner.mdx) |
| **Mandatory run variables** | `documents`: A list of documents to split each into smaller documents based on embedding similarity. |
| **Output variables** | `documents`: A list of documents |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/embedding_based_document_splitter.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
This component splits documents based on embedding similarity using cosine distances between sequential sentence groups.
It first splits text into sentences, optionally groups them, calculates embeddings for each group, and then uses cosine
distance between sequential embeddings to determine split points. Any distance above the specified percentile is treated
as a break point. The component also tracks page numbers based on form feed characters (`\f`) in the original document.
This component is inspired by [5 Levels of Text Splitting](https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb) by Greg Kamradt.
## Usage
### On its own
```python
from haystack import Document
from haystack.components.embedders import SentenceTransformersDocumentEmbedder
from haystack.components.preprocessors import EmbeddingBasedDocumentSplitter
# Create a document with content that has a clear topic shift
doc = Document(
content="This is a first sentence. This is a second sentence. This is a third sentence. "
"Completely different topic. The same completely different topic.",
)
# Initialize the embedder to calculate semantic similarities
embedder = SentenceTransformersDocumentEmbedder()
# Configure the splitter with parameters that control splitting behavior
splitter = EmbeddingBasedDocumentSplitter(
document_embedder=embedder,
sentences_per_group=2, # Group 2 sentences before calculating embeddings
percentile=0.95, # Split when cosine distance exceeds 95th percentile
min_length=50, # Merge splits shorter than 50 characters
max_length=1000, # Further split chunks longer than 1000 characters
)
result = splitter.run(documents=[doc])
# The result contains a list of Document objects, each representing a semantic chunk
# Each split document includes metadata: source_id, split_id, and page_number
print(f"Original document split into {len(result['documents'])} chunks")
for i, split_doc in enumerate(result["documents"]):
print(f"Chunk {i}: {split_doc.content[:50]}...")
```
### In a pipeline
```python
from pathlib import Path
from haystack import Document
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters.txt import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.preprocessors import EmbeddingBasedDocumentSplitter
from haystack.components.writers import DocumentWriter
document_store = InMemoryDocumentStore()
Pipeline = Pipeline()
Pipeline.add_component(instance=TextFileToDocument(), name="text_file_converter")
Pipeline.add_component(instance=DocumentCleaner(), name="cleaner")
Pipeline.add_component(instance=EmbeddingBasedDocumentSplitter(document_embedder=embedder, sentences_per_group=2, percentile=0.95, min_length=50,max_length=1000)
Pipeline.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
Pipeline.connect("text_file_converter.documents", "cleaner.documents")
Pipeline.connect("cleaner.documents", "splitter.documents")
Pipeline.connect("splitter.documents", "writer.documents")
path = "path/to/your/files"
files = list(Path(path).glob("*.md"))
Pipeline.run({"text_file_converter": {"sources": files}})
```
@@ -0,0 +1,98 @@
---
title: "HierarchicalDocumentSplitter"
id: hierarchicaldocumentsplitter
slug: "/hierarchicaldocumentsplitter"
description: "Use this component to create a multi-level document structure based on parent-children relationships between text segments."
---
# HierarchicalDocumentSplitter
Use this component to create a multi-level document structure based on parent-children relationships between text segments.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) and [`DocumentCleaner`](documentcleaner.mdx) |
| **Mandatory init variables** | `block_sizes`: Set of block sizes to split the document into. The blocks are split in descending order. |
| **Mandatory run variables** | `documents`: A list of documents to split into hierarchical blocks |
| **Output variables** | `documents`: A list of hierarchical documents |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | [https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/hierarchical_document_splitter.py](https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/hierarchical_document_splitter.py#L12) |
| **Package name** | `haystack-ai` |
</div>
## Overview
The `HierarchicalDocumentSplitter` divides documents into blocks of different sizes, creating a tree-like structure.
A block is one of the chunks of text that the splitter produces. It is similar to cutting a long piece of text into smaller pieces: each piece is a block. Blocks form a tree structure where your full document is the root block, and as you split it into smaller and smaller pieces you get child-blocks and leaf-blocks, down to whatever smallest size specified.
The [`AutoMergingRetriever`](../retrievers/automergingretriever.mdx) component then leverages this hierarchical structure to improve document retrieval.
To initialize the component, you need to specify the `block_size`, which is the “maximum length” of each of the blocks, measured in the specific unit (see `split_by` parameter). Pass a set of sizes (for example, `{20, 5}`), and it will:
- First, split the document into blocks of up to 20 units each (the “parent” blocks).
- Then, it will split each of those into blocks of up to 5 units each (the “child” blocks).
This descending order of sizes builds the hierarchy.
These additional parameters can be set when the component is initialized:
- `split_by` can be `"word"` (default), `"sentence"`, `"passage"`, `"page"`.
- `split_overlap` is an integer indicating the number of overlapping words, sentences, or passages between chunks, 0 being the default.
## Usage
### On its own
```python
from haystack import Document
from haystack.components.preprocessors import HierarchicalDocumentSplitter
doc = Document(content="This is a simple test document")
splitter = HierarchicalDocumentSplitter(block_sizes={3, 2}, split_overlap=0, split_by="word")
splitter.run([doc])
>> {'documents': [Document(id=3f7..., content: 'This is a simple test document', meta: {'block_size': 0, 'parent_id': None, 'children_ids': ['5ff..', '8dc..'], 'level': 0}),
>> Document(id=5ff.., content: 'This is a ', meta: {'block_size': 3, 'parent_id': '3f7..', 'children_ids': ['f19..', '52c..'], 'level': 1, 'source_id': '3f7..', 'page_number': 1, 'split_id': 0, 'split_idx_start': 0}),
>> Document(id=8dc.., content: 'simple test document', meta: {'block_size': 3, 'parent_id': '3f7..', 'children_ids': ['39d..', 'e23..'], 'level': 1, 'source_id': '3f7..', 'page_number': 1, 'split_id': 1, 'split_idx_start': 10}),
>> Document(id=f19.., content: 'This is ', meta: {'block_size': 2, 'parent_id': '5ff..', 'children_ids': [], 'level': 2, 'source_id': '5ff..', 'page_number': 1, 'split_id': 0, 'split_idx_start': 0}),
>> Document(id=52c.., content: 'a ', meta: {'block_size': 2, 'parent_id': '5ff..', 'children_ids': [], 'level': 2, 'source_id': '5ff..', 'page_number': 1, 'split_id': 1, 'split_idx_start': 8}),
>> Document(id=39d.., content: 'simple test ', meta: {'block_size': 2, 'parent_id': '8dc..', 'children_ids': [], 'level': 2, 'source_id': '8dc..', 'page_number': 1, 'split_id': 0, 'split_idx_start': 0}),
>> Document(id=e23.., content: 'document', meta: {'block_size': 2, 'parent_id': '8dc..', 'children_ids': [], 'level': 2, 'source_id': '8dc..', 'page_number': 1, 'split_id': 1, 'split_idx_start': 12})]}
```
### In a pipeline
This Haystack pipeline processes `.md` files by converting them to documents, cleaning the text, splitting it into sentence-based chunks, and storing the results in an In-Memory Document Store.
```python
from pathlib import Path
from haystack import Document
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters.txt import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.preprocessors import HierarchicalDocumentSplitter
from haystack.components.writers import DocumentWriter
document_store = InMemoryDocumentStore()
Pipeline = Pipeline()
Pipeline.add_component(instance=TextFileToDocument(), name="text_file_converter")
Pipeline.add_component(instance=DocumentCleaner(), name="cleaner")
Pipeline.add_component(instance=HierarchicalDocumentSplitter(
block_sizes={10, 6, 3}, split_overlap=0, split_by="sentence", name="splitter"
)
Pipeline.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
Pipeline.connect("text_file_converter.documents", "cleaner.documents")
Pipeline.connect("cleaner.documents", "splitter.documents")
Pipeline.connect("splitter.documents", "writer.documents")
path = "path/to/your/files"
files = list(Path(path).glob("*.md"))
Pipeline.run({"text_file_converter": {"sources": files}})
```
@@ -0,0 +1,123 @@
---
title: "MarkdownHeaderSplitter"
id: markdownheadersplitter
slug: "/markdownheadersplitter"
description: "Split documents at ATX-style Markdown headers (#), with optional secondary splitting. Preserves header hierarchy as metadata."
---
# MarkdownHeaderSplitter
Split documents at ATX-style Markdown headers (`#`, `##`, and so on), with optional secondary splitting. Header hierarchy is preserved as metadata on each chunk.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In indexing pipelines after [Converters](../converters.mdx) and [`DocumentCleaner`](documentcleaner.mdx) |
| **Mandatory run variables** | `documents`: A list of text documents to split. |
| **Output variables** | `documents`: A list of documents split at headers (and optionally by secondary split). |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | [https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/markdown_header_splitter.py](https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/markdown_header_splitter.py) |
| **Package name** | `haystack-ai` |
</div>
## Overview
The `MarkdownHeaderSplitter` processes text documents by:
- Splitting them into chunks at ATX-style Markdown headers (`#`, `##`, …, `######`), preserving header hierarchy as metadata.
- Optionally applying a secondary split (by word, passage, period, or line) to each chunk using Haystack's [`DocumentSplitter`](documentsplitter.mdx).
- Preserving and propagating metadata such as parent headers, page numbers, and split IDs.
Only ATX-style headers are recognized (e.g. `# Title`). Setext-style headers (`Underline with ===`) aren't supported.
Parameters you can set when initializing the component:
- `page_break_character`: Character used to identify page breaks. Defaults to form feed `\f`.
- `keep_headers`: If `True`, headers remain in the chunk content. If `False`, headers are moved to metadata only. Defaults to `True`.
- `secondary_split`: Optional secondary split after header splitting. Options: `None`, `"word"`, `"passage"`, `"period"`, `"line"`. Defaults to `None`.
- `split_length`: Maximum number of units per split when using secondary splitting. Defaults to `200`.
- `split_overlap`: Number of overlapping units between splits when using secondary splitting. Defaults to `0`.
- `split_threshold`: Minimum number of units per split when using secondary splitting. Defaults to `0`.
- `skip_empty_documents`: Whether to skip documents with empty content. Defaults to `True`.
Each output document's metadata includes:
- `source_id`: ID of the original document.
- `page_number`: Page number. Updated when `page_break_character` is found.
- `split_id`: Index of the chunk within its parent.
- `header`: The header text for this chunk.
- `parent_headers`: List of parent header texts in hierarchy order.
The component only works with text documents. Documents with `None` or non-string content raise a `ValueError`.
## Usage
### On its own
```python
from haystack import Document
from haystack.components.preprocessors import MarkdownHeaderSplitter
text = (
"# Introduction\n"
"This is the intro section.\n"
"## Getting Started\n"
"Here is how to start.\n"
"## Advanced\n"
"Advanced content here."
)
doc = Document(content=text)
splitter = MarkdownHeaderSplitter(keep_headers=True)
result = splitter.run(documents=[doc])
# result["documents"] contains one document per header section,
# with meta["header"], meta["parent_headers"], meta["source_id"], and so on
```
### With secondary splitting
When sections are long, you can add a secondary split, for example by word, so each chunk stays within a maximum size:
```python
from haystack import Document
from haystack.components.preprocessors import MarkdownHeaderSplitter
text = "# Section\n" + "Some long body text. " * 50
doc = Document(content=text)
splitter = MarkdownHeaderSplitter(
keep_headers=True,
secondary_split="word",
split_length=20,
split_overlap=2,
)
result = splitter.run(documents=[doc])
```
### In a pipeline
This pipeline converts Markdown files to documents, cleans them, splits by headers, and writes to an in-memory document store:
```python
from pathlib import Path
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters.txt import TextFileToDocument
from haystack.components.preprocessors import MarkdownHeaderSplitter
from haystack.components.writers import DocumentWriter
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component("text_file_converter", TextFileToDocument())
p.add_component("splitter", MarkdownHeaderSplitter(keep_headers=True))
p.add_component("writer", DocumentWriter(document_store=document_store))
p.connect("text_file_converter.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
path = "path/to/your/files"
files = list(Path(path).glob("*.md"))
p.run({"text_file_converter": {"sources": files}})
```
@@ -0,0 +1,147 @@
---
title: "PresidioDocumentCleaner"
id: presidiodocumentcleaner
slug: "/presidiodocumentcleaner"
description: "Use `PresidioDocumentCleaner` to replace PII in Document text with entity type placeholders, powered by Microsoft Presidio."
---
# PresidioDocumentCleaner
`PresidioDocumentCleaner` replaces personally identifiable information (PII) in the text content of Documents with entity type placeholders such as `<PERSON>` or `<EMAIL_ADDRESS>`. Original Documents are not mutated. Documents without text content pass through unchanged.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In an indexing pipeline, before writing Documents to a Document Store |
| **Mandatory run variables** | `documents`: A list of Document objects |
| **Output variables** | `documents`: A list of Document objects with PII replaced |
| **API reference** | [Presidio](/reference/integrations-presidio) |
| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/presidio |
| **Package name** | `presidio-haystack` |
</div>
## Overview
[Microsoft Presidio](https://microsoft.github.io/presidio/) is an open-source framework for PII detection and anonymization. `PresidioDocumentCleaner` uses Presidio's Analyzer and Anonymizer engines to scan document text and replace detected entities with type placeholders such as `<PERSON>` or `<EMAIL_ADDRESS>`.
This is useful when you want to store sanitized versions of your documents in a Document Store — for example, to prevent sensitive information from being indexed or returned in search results.
If you want to annotate PII without modifying the text, see [`PresidioEntityExtractor`](../extractors/presidioentityextractor.mdx). For sanitizing plain strings such as user queries, see [`PresidioTextCleaner`](./presidiotextcleaner.mdx).
## Configuration
| Parameter | Default | Description |
| --- | --- | --- |
| `language` | `"en"` | ISO 639-1 language code for PII detection. The appropriate spaCy model is selected automatically for [supported languages](#non-english-languages). See [Presidio supported languages](https://microsoft.github.io/presidio/analyzer/languages/). |
| `entities` | `None` | List of PII entity types to detect and anonymize (e.g. `["PERSON", "EMAIL_ADDRESS"]`). If `None`, all supported types are detected. See [supported entities](https://microsoft.github.io/presidio/supported_entities/). |
| `score_threshold` | `0.35` | Minimum confidence score (01) for a detected entity to be anonymized. |
| `models` | `None` | Advanced override: explicit list of spaCy model configs, e.g. `[{"lang_code": "fr", "model_name": "fr_core_news_md"}]`. Use this only when you need a specific model variant or a language not in the built-in mapping. If `None`, the model is selected automatically based on `language`. |
## Usage
Install the `presidio-haystack` package to use the `PresidioDocumentCleaner`.
```bash
pip install presidio-haystack
```
### On its own
```python
from haystack import Document
from haystack_integrations.components.preprocessors.presidio import (
PresidioDocumentCleaner,
)
cleaner = PresidioDocumentCleaner()
result = cleaner.run(
documents=[
Document(content="Contact Alice Smith at alice@example.com or 212-555-1234."),
],
)
print(result["documents"][0].content)
# Contact <PERSON> at <EMAIL_ADDRESS> or <PHONE_NUMBER>.
```
### In a pipeline
```python
from haystack import Document, Pipeline
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack_integrations.components.preprocessors.presidio import (
PresidioDocumentCleaner,
)
document_store = InMemoryDocumentStore()
indexing_pipeline = Pipeline()
indexing_pipeline.add_component("cleaner", PresidioDocumentCleaner())
indexing_pipeline.add_component("writer", DocumentWriter(document_store=document_store))
indexing_pipeline.connect("cleaner", "writer")
indexing_pipeline.run(
{
"cleaner": {
"documents": [
Document(content="Alice Smith's email is alice@example.com"),
Document(content="Call Bob at 212-555-9876"),
],
},
},
)
```
### Using Custom Parameters
Use `entities` to limit anonymization to the PII types you actually care about. This reduces false positives and improves performance by skipping recognizers you don't need.
Use `score_threshold` to tune the precision-recall tradeoff. The default `0.35` casts a wide net and may anonymize some false positives. Raise it (e.g. `0.7`) when you need high confidence before replacing text; lower it when missing any PII is the bigger risk.
```python
from haystack_integrations.components.preprocessors.presidio import (
PresidioDocumentCleaner,
)
cleaner = PresidioDocumentCleaner(
language="de",
entities=["PERSON", "EMAIL_ADDRESS"], # only anonymize names and emails
score_threshold=0.7, # higher precision, fewer false positives
)
```
### Non-English languages
For any language in the built-in mapping, just set `language` — the right spaCy model is selected and loaded automatically at warm-up time.
```python
from haystack import Document
from haystack_integrations.components.preprocessors.presidio import (
PresidioDocumentCleaner,
)
# No `models` parameter needed — de_core_news_lg is selected automatically
cleaner = PresidioDocumentCleaner(language="de")
result = cleaner.run(
documents=[
Document(
content="Mein Name ist Hans Müller und meine E-Mail ist hans@example.com",
),
],
)
print(result["documents"][0].content)
# Mein Name ist <PERSON> und meine E-Mail ist <EMAIL_ADDRESS>
```
Supported languages and their default models are listed in `PresidioDocumentCleaner.SPACY_DEFAULT_MODELS`. Using a language not in that mapping without providing `models` raises a `ValueError` at warm-up time with a list of the supported language codes.
To use a non-default model variant, or a language outside the built-in mapping, pass `models` explicitly:
```python
cleaner = PresidioDocumentCleaner(
language="fr",
models=[{"lang_code": "fr", "model_name": "fr_core_news_md"}],
)
```
@@ -0,0 +1,125 @@
---
title: "PresidioTextCleaner"
id: presidiotextcleaner
slug: "/presidiotextcleaner"
description: "Use `PresidioTextCleaner` to replace PII in plain strings, powered by Microsoft Presidio."
---
# PresidioTextCleaner
`PresidioTextCleaner` replaces personally identifiable information (PII) in plain strings. It takes a `list[str]` as input and returns a `list[str]`, making it easy to sanitize user queries before they are sent to an LLM.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | In a query pipeline, before a Generator or Chat Generator |
| **Mandatory run variables** | `texts`: A list of strings |
| **Output variables** | `texts`: A list of strings with PII replaced |
| **API reference** | [Presidio](/reference/integrations-presidio) |
| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/presidio |
| **Package name** | `presidio-haystack` |
</div>
## Overview
[Microsoft Presidio](https://microsoft.github.io/presidio/) is an open-source framework for PII detection and anonymization. `PresidioTextCleaner` uses Presidio's Analyzer and Anonymizer engines to scan plain text strings and replace detected entities with type placeholders such as `<PERSON>` or `<US_SSN>`.
This is useful when you want to sanitize user queries before sending them to an LLM, ensuring that no personally identifiable information is passed to the model.
For sanitizing Haystack `Document` objects rather than plain strings, see [`PresidioDocumentCleaner`](./presidiodocumentcleaner.mdx).
## Configuration
| Parameter | Default | Description |
| --- | --- | --- |
| `language` | `"en"` | ISO 639-1 language code for PII detection. The appropriate spaCy model is selected automatically for [supported languages](#non-english-languages). See [Presidio supported languages](https://microsoft.github.io/presidio/analyzer/languages/). |
| `entities` | `None` | List of PII entity types to detect and anonymize (e.g. `["PERSON", "EMAIL_ADDRESS"]`). If `None`, all supported types are detected. See [supported entities](https://microsoft.github.io/presidio/supported_entities/). |
| `score_threshold` | `0.35` | Minimum confidence score (01) for a detected entity to be anonymized. |
| `models` | `None` | Advanced override: explicit list of spaCy model configs, e.g. `[{"lang_code": "fr", "model_name": "fr_core_news_md"}]`. Use this only when you need a specific model variant or a language not in the built-in mapping. If `None`, the model is selected automatically based on `language`. |
## Usage
Install the `presidio-haystack` package to use the `PresidioTextCleaner`.
```bash
pip install presidio-haystack
```
### On its own
```python
from haystack_integrations.components.preprocessors.presidio import PresidioTextCleaner
cleaner = PresidioTextCleaner()
result = cleaner.run(texts=["My name is John Doe, my SSN is 123-45-6789"])
print(result["texts"][0])
# My name is <PERSON>, my SSN is <US_SSN>
```
### In a pipeline
```python
from haystack import Pipeline
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack_integrations.components.preprocessors.presidio import PresidioTextCleaner
template = [ChatMessage.from_user("Answer this question: {{query}}")]
query_pipeline = Pipeline()
query_pipeline.add_component("cleaner", PresidioTextCleaner())
query_pipeline.add_component("prompt_builder", ChatPromptBuilder(template=template))
query_pipeline.add_component("llm", OpenAIChatGenerator(model="gpt-4o-mini"))
query_pipeline.connect("cleaner.texts[0]", "prompt_builder.query")
query_pipeline.connect("prompt_builder", "llm")
query_pipeline.run(
{"cleaner": {"texts": ["My name is John Smith. What is the capital of France?"]}},
)
```
### Using Custom Parameters
Use `entities` to limit anonymization to the PII types you actually care about. This reduces false positives and improves performance by skipping recognizers you don't need.
Use `score_threshold` to tune the precision-recall tradeoff. The default `0.35` casts a wide net and may anonymize some false positives. Raise it (e.g. `0.7`) when you need high confidence before replacing text; lower it when missing any PII is the bigger risk.
```python
from haystack_integrations.components.preprocessors.presidio import PresidioTextCleaner
cleaner = PresidioTextCleaner(
language="de",
entities=["PERSON", "EMAIL_ADDRESS"], # only anonymize names and emails
score_threshold=0.7, # higher precision, fewer false positives
)
```
### Non-English languages
For any language in the built-in mapping, just set `language` — the right spaCy model is selected and loaded automatically at warm-up time.
```python
from haystack_integrations.components.preprocessors.presidio import PresidioTextCleaner
# No `models` parameter needed — de_core_news_lg is selected automatically
cleaner = PresidioTextCleaner(language="de")
result = cleaner.run(
texts=["Hallo, ich bin Thomas Schmidt und meine E-Mail ist thomas@example.com"],
)
print(result["texts"][0])
# Hallo, ich bin <PERSON> und meine E-Mail ist <EMAIL_ADDRESS>
```
Supported languages and their default models are listed in `PresidioTextCleaner.SPACY_DEFAULT_MODELS`. Using a language not in that mapping without providing `models` raises a `ValueError` at warm-up time with a list of the supported language codes.
To use a non-default model variant, or a language outside the built-in mapping, pass `models` explicitly:
```python
cleaner = PresidioTextCleaner(
language="fr",
models=[{"lang_code": "fr", "model_name": "fr_core_news_md"}],
)
```
@@ -0,0 +1,99 @@
---
title: "RecursiveDocumentSplitter"
id: recursivesplitter
slug: "/recursivesplitter"
description: "This component recursively breaks down text into smaller chunks by applying a given list of separators to the text."
---
# RecursiveDocumentSplitter
This component recursively breaks down text into smaller chunks by applying a given list of separators to the text.
<div className="key-value-table">
| | |
| --- | --- |
| Most common position in a pipeline | In indexing pipelines after [Converters](../converters.mdx) and [`DocumentCleaner`](documentcleaner.mdx) , before [Classifiers](../classifiers.mdx) |
| Mandatory run variables | `documents`: A list of documents |
| Output variables | `documents`: A list of documents |
| API reference | [PreProcessors](/reference/preprocessors-api) |
| Github link | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/recursive_splitter.py |
</div>
## Overview
The `RecursiveDocumentSplitter` expects a list of documents as input and returns a list of documents with split texts. You can set the following parameters when initializing the component:
- `split_length`: The maximum length of each chunk, in words, by default. See the `split_units` parameter to change the the unit.
- `split_overlap`: The number of characters or words that overlap between consecutive chunks.
- `split_unit`: The unit of the `split_length` parameter. Can be either `"word"`, `"char"`, or `"token"`.
- `separators`: An optional list of separator strings to use for splitting the text. If you dont provide any separators, the default ones are `["\n\n", "sentence", "\n", " "]`. The string separators will be treated as regular expressions. If the separator is `"sentence"`, the text will be split into sentences using a custom sentence tokenizer based on NLTK. See [SentenceSplitter](https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/sentence_tokenizer.py#L116) code for more information.
- `sentence_splitter_params`: Optional parameters to pass to the [SentenceSplitter](https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/sentence_tokenizer.py#L116).
The separators are applied in the same order as they are defined in the list. The first separator is used on the text; any resulting chunk that is within the specified `chunk_size` is retained. For chunks that exceed the defined `chunk_size`, the next separator in the list is applied. If all separators are used and the chunk still exceeds the `chunk_size`, a hard split occurs based on the `chunk_size`, taking into account whether words or characters are used as counting units. This process is repeated until all chunks are within the limits of the specified `chunk_size`.
## Usage
```python
from haystack import Document
from haystack.components.preprocessors import RecursiveDocumentSplitter
chunker = RecursiveDocumentSplitter(split_length=260, split_overlap=0, separators=["\n\n", "\n", ".", " "])
text = ('''Artificial intelligence (AI) - Introduction
AI, in its broadest sense, is intelligence exhibited by machines, particularly computer systems.
AI technology is widely used throughout industry, government, and science. Some high-profile applications include advanced web search engines; recommendation systems; interacting via human speech; autonomous vehicles; generative and creative tools; and superhuman play and analysis in strategy games.''')
doc = Document(content=text)
doc_chunks = chunker.run([doc])
print(doc_chunks["documents"])
>[
>Document(id=..., content: 'Artificial intelligence (AI) - Introduction\n\n', meta: {'original_id': '...', 'split_id': 0, 'split_idx_start': 0, '_split_overlap': []})
>Document(id=..., content: 'AI, in its broadest sense, is intelligence exhibited by machines, particularly computer systems.\n', meta: {'original_id': '...', 'split_id': 1, 'split_idx_start': 45, '_split_overlap': []})
>Document(id=..., content: 'AI technology is widely used throughout industry, government, and science.', meta: {'original_id': '...', 'split_id': 2, 'split_idx_start': 142, '_split_overlap': []})
>Document(id=..., content: ' Some high-profile applications include advanced web search engines; recommendation systems; interac...', meta: {'original_id': '...', 'split_id': 3, 'split_idx_start': 216, '_split_overlap': []})
>]
```
### In a pipeline
Here's how you can use `RecursiveSplitter` in an indexing pipeline:
```python
from pathlib import Path
from haystack import Document
from haystack import Pipeline
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.converters.txt import TextFileToDocument
from haystack.components.preprocessors import DocumentCleaner
from haystack.components.preprocessors import RecursiveDocumentSplitter
from haystack.components.writers import DocumentWriter
document_store = InMemoryDocumentStore()
p = Pipeline()
p.add_component(instance=TextFileToDocument(), name="text_file_converter")
p.add_component(instance=DocumentCleaner(), name="cleaner")
p.add_component(
instance=RecursiveDocumentSplitter(
split_length=400,
split_overlap=0,
split_unit="char",
separators=["\n\n", "\n", "sentence", " "],
sentence_splitter_params={
"language": "en",
"use_split_rules": True,
"keep_white_spaces": False,
},
),
name="recursive_splitter",
)
p.add_component(instance=DocumentWriter(document_store=document_store), name="writer")
p.connect("text_file_converter.documents", "cleaner.documents")
p.connect("cleaner.documents", "splitter.documents")
p.connect("splitter.documents", "writer.documents")
path = "path/to/your/files"
files = list(Path(path).glob("*.md"))
p.run({"text_file_converter": {"sources": files}})
```
@@ -0,0 +1,120 @@
---
title: "TextCleaner"
id: textcleaner
slug: "/textcleaner"
description: "Use `TextCleaner` to make text data more readable. It removes regexes, punctuation, and numbers, as well as converts text to lowercase. This is especially useful to clean up text data before evaluation."
---
# TextCleaner
Use `TextCleaner` to make text data more readable. It removes regexes, punctuation, and numbers, as well as converts text to lowercase. This is especially useful to clean up text data before evaluation.
<div className="key-value-table">
| | |
| --- | --- |
| **Most common position in a pipeline** | Between a [Generator](../generators.mdx) and an [Evaluator](../evaluators.mdx) |
| **Mandatory run variables** | `texts`: A list of strings to be cleaned |
| **Output variables** | `texts`: A list of cleaned texts |
| **API reference** | [PreProcessors](/reference/preprocessors-api) |
| **GitHub link** | https://github.com/deepset-ai/haystack/blob/main/haystack/components/preprocessors/text_cleaner.py |
| **Package name** | `haystack-ai` |
</div>
## Overview
`TextCleaner` expects a list of strings as input and returns a list of strings with cleaned texts. Selectable cleaning steps are to `convert_to_lowercase`, `remove_punctuation`, and to `remove_numbers`. These three parameters are booleans that need to be set when the component is initialized.
- `convert_to_lowercase` converts all characters in texts to lowercase.
- `remove_punctuation` removes all punctuation from the text.
- `remove_numbers` removes all numerical digits from the text.
In addition, you can specify a regular expression with the parameter `remove_regexps`, and any matches will be removed.
## Usage
### On its own
You can use it outside of a pipeline to clean up any texts:
```python
from haystack.components.preprocessors import TextCleaner
text_to_clean = (
"1Moonlight shimmered softly, 300 Wolves howled nearby, Night enveloped everything."
)
cleaner = TextCleaner(
convert_to_lowercase=True,
remove_punctuation=False,
remove_numbers=True,
)
result = cleaner.run(texts=[text_to_clean])
```
### In a pipeline
In this example, we are using `TextCleaner` after an `ExtractiveReader` and an `OutputAdapter` to remove the punctuation in texts. Then, our custom-made `ExactMatchEvaluator` component compares the retrieved answer to the ground truth answer.
```python
from typing import List
from haystack import component, Document, Pipeline
from haystack.components.converters import OutputAdapter
from haystack.components.preprocessors import TextCleaner
from haystack.components.readers import ExtractiveReader
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack.document_stores.in_memory import InMemoryDocumentStore
document_store = InMemoryDocumentStore()
documents = [
Document(content="There are over 7,000 languages spoken around the world today."),
Document(
content="Elephants have been observed to behave in a way that indicates a high level of self-awareness, such as recognizing themselves in mirrors.",
),
Document(
content="In certain parts of the world, like the Maldives, Puerto Rico, and San Diego, you can witness the phenomenon of bioluminescent waves.",
),
]
document_store.write_documents(documents=documents)
@component
class ExactMatchEvaluator:
@component.output_types(score=int)
def run(self, expected: str, provided: List[str]):
return {"score": int(expected in provided)}
adapter = OutputAdapter(
template="{{answers | extract_data}}",
output_type=List[str],
custom_filters={
"extract_data": lambda data: [answer.data for answer in data if answer.data],
},
)
p = Pipeline()
p.add_component("retriever", InMemoryBM25Retriever(document_store=document_store))
p.add_component("reader", ExtractiveReader())
p.add_component("adapter", adapter)
p.add_component("cleaner", TextCleaner(remove_punctuation=True))
p.add_component("evaluator", ExactMatchEvaluator())
p.connect("retriever", "reader")
p.connect("reader", "adapter")
p.connect("adapter", "cleaner.texts")
p.connect("cleaner", "evaluator.provided")
question = "What behavior indicates a high level of self-awareness of elephants?"
ground_truth_answer = "recognizing themselves in mirrors"
result = p.run(
{
"retriever": {"query": question},
"reader": {"query": question},
"evaluator": {"expected": ground_truth_answer},
},
)
print(result)
```