Dataset Segmentation Configuration#
Segmentation (chunking) is configured during Step 2 of knowledge base document creation. It controls how raw documents are split into indexable chunks before being embedded and stored. The mode and parameters chosen here directly determine chunk granularity, retrieval quality, and the shape of the indexing pipeline.
Key entry points:
- UI:
step-two/index.tsxβ renders mode-specific option cards - Backend runner:
IndexingRunner.run()β drives the Extract β Clean β Segment β Index pipeline - Celery task:
_document_indexing()β async entry point
Chunking Modes#
Three modes are defined by the ChunkingMode enum , which maps to the doc_form API field :
| UI Label | ChunkingMode value | doc_form string |
|---|---|---|
| General (text) | text | text_model |
| General (QA) | qa | qa_model |
| Parent-Child | parentChild | hierarchical_model |
Note: The QA mode is only available on Community/Enterprise (non-cloud) editions .
General Mode#
Configured via GeneralChunkingOptions . Exposes three core fields rendered by inputs.tsx :
- Separator (
segmentIdentifier) β delimiter string; supports escape sequences (e.g.\n\n). Rendered viaDelimiterInput. - Max chunk length (
maxChunkLength) β upper-bounded byNEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTHenv var; minimum 1 . - Overlap (
overlap) β characters of overlap between adjacent chunks; minimum 1 .
Automatic mode defaults (set by DatasetProcessRule.AUTOMATIC_RULES): delimiter \n, max tokens 500, chunk overlap 50 .
Parent-Child Mode#
Configured via parent-child-options.tsx . Offers two parent modes selected via RadioGroup :
| Parent Mode | Behavior |
|---|---|
paragraph | Document is split into paragraph-sized parent chunks; each parent is further split into child chunks |
full-doc | Entire document is one parent; child chunks are subsets of it |
The ParentMode type is a string union 'full-doc' | 'paragraph' . Child chunk settings (delimiter, max length) are configured separately from parent settings.
Backend: Text Splitter Selection#
_get_splitter() in index_processor_base.py selects the splitter based on process_rule.mode :
process_rule.mode | Splitter class | Notes |
|---|---|---|
custom or hierarchical | FixedRecursiveCharacterTextSplitter | Uses user-defined separator + fallback chain |
automatic | EnhanceRecursiveCharacterTextSplitter | Uses default rules |
The max_tokens parameter is validated to be between 50 and INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH before being passed as chunk_size .
FixedRecursiveCharacterTextSplitter#
Defined in api/core/rag/splitter/fixed_text_splitter.py . Behavior:
- Split by the user-defined
fixed_separatorfirst (escape sequences decoded viacodecs.decode). - Chunks exceeding
chunk_sizeare recursively split using a fallback separator chain:["\n\n", "\n", "γ", ". ", " ", ""]β which covers CJK punctuation and space for multilingual text.
Previously Known Issue (Fixed in PR #39498): When recursive splitting fell through to the space (" ") separator, re.split(r" +", text) stripped the spaces, and the keep_separator restoration ran only in the non-space branch. Merged chunks then lost word-boundary spaces. Affected Korean, and any language relying on spaces when chunks exceeded size limits. Issue #39403 was resolved by PR #39498, which corrected the indentation so that the keep_separator logic applies to all separators including spaces. Spaces are now correctly preserved during recursive splitting when keep_separator is enabled.
Indexing Pipeline Effect#
After segmentation, chunks flow into the index stage via IndexingRunner._load() :
high_qualityβ chunks are embedded via the dataset's embedding model and written to the vector store (parallelized across 10 threads).economyβ keyword index built with Jieba; no embeddings.
Parent-Child mode diverges at the index processor level. ParentChildIndexProcessor only embeds and stores child chunks in the vector store; parent chunks are stored in document_segments unembedded. At query time, child doc_ids are looked up β ChildChunk.segment_id β parent DocumentSegment returned to the LLM .
Known bug (open as of 2026-07-25): Token counting during indexing sends all chunks to the embedding plugin in a single unbatched request, unlike the embedding step which batches by MAX_CHUNKS. For large documents (thousands of chunks), this can trigger HTTP 413 errors or OOM-kill the plugin daemon. Tracked in #39560 . The embedding call itself is already correctly batched in cached_embedding.py.
Pre-Processing Rules#
Applied before splitting by CleanProcessor.clean() . Configurable in the UI via checkboxes in GeneralChunkingOptions :
| Rule ID | Effect |
|---|---|
remove_extra_spaces | Collapses 3+ consecutive newlines β 2; multiple horizontal spaces β one space |
remove_urls_emails | Strips bare URLs and email addresses; preserves Markdown link/image syntax |
remove_stopwords | Removes stopwords (language-dependent) |
API Configuration Reference#
When creating documents via the Service API, segmentation is controlled through the process_rule field of the request payload :
{
"doc_form": "text_model", // or "hierarchical_model"
"indexing_technique": "high_quality",
"process_rule": {
"mode": "custom", // "automatic" | "custom" | "hierarchical"
"rules": {
"pre_processing_rules": [
{ "id": "remove_extra_spaces", "enabled": true },
{ "id": "remove_urls_emails", "enabled": false }
],
"segmentation": {
"delimiter": "\n\n",
"max_tokens": 500,
"chunk_overlap": 50
}
}
}
}
If process_rule is omitted, the dataset's most recent process rule is reused. For hierarchical mode, set doc_form: "hierarchical_model" and include parent/child-specific segmentation config. Indexing is asynchronous β poll GET /datasets/{dataset_id}/documents/{batch}/indexing-status for progress through stages: waiting β parsing β cleaning β splitting β indexing β completed .