docling-project / docling-project/docling
Merge Very Short Chunks Below a Minimum Token Threshold in HybridChunker
- Dominant language
- Python
- Stars
- 66.4k
- Forks
- 4.8k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 84
Description
### Requested Feature
We’d like to request an enhancement to `HybridChunker` to allow merging of very short chunks (e.g., below a configurable minimum token threshold) into larger, more coherent chunks, even if they don’t share identical metadata like headings. Currently, with `merge_peers=True`, undersized chunks are merged only when they share the same relevant metadata, but we’re seeing many standalone short chunks—sometimes just a single sentence or a few words—that reduce the coherence and utility of our downstream embeddings and retrieval tasks.
**Proposed Feature**: Add a `min_tokens` parameter to `HybridChunker` (e.g., defaulting to 20 tokens) that triggers merging of chunks with fewer tokens than this threshold into the nearest preceding or following chunk, regardless of metadata similarity, as long as the resulting chunk stays under `max_tokens` (512 in our case with `SCAI-BIO/bio-gottbert-base`). This would improve readability and context for short chunks like links or brief statements.
**User Need**: We process German medical PDFs, and short chunks (e.g., “Hintergründe zu Ursachen, Symptomen, Verlauf und Behandlung uvm. finden Sie auf dem Gesundheitsportal des Bmg.” or “Hier gelangen Sie zur Seite des Deutschen Diabetes-Zentrums.”) often lack sufficient context when embedded separately. Merging them into larger chunks (e.g., up to “Hier gelangen Sie zur Seite des Deutschen Zentrums für Diabetesforschung. Hintergründe zu Risikofaktoren, Folgen und Diagnose auf der Internetseite. Stand: November”) would enhance the quality of our vector store and retrieval results.
**Example from Logs**:
Here’s a sample of chunks from our pipeline, showing short chunks we’d like to merge:
```
2025-03-17 21:40:49,217 - 248 - ['Typ-2-Diabetes']
2025-03-17 21:40:49,217 - 249 - entsteht zum einen durch eine verminderte Empfindlichkeit der Körperzellen für Insulin (Insulinresistenz), zum anderen führt eine jahrelange Überproduktion von Insulin zu einer "Erschöpfung" der insulinproduzierenden Zellen (die Bauchspeicheldrüse kann nicht genügend Insulin für den erhöhten Bedarf liefern), beginnt meist schleichend, wurde früher auch als "Altersdiabetes" bezeichnet, jedoch erkranken in den letzten Jahren auch zunehmend junge Erwachsene, sogar Jugendliche daran. Neben einer erblichen Veranlagung gelten Übergewicht und Bewegungsmangel als die wichtigsten Verursacher eines Typ-2-Diabetes. Aber auch eine unausgewogene (ballaststoffarme, fett-und zuckerreiche) Ernährung und Rauchen begünstigen die Entstehung von Typ-2-Diabetes. Es stehen verschiedene Therapiebausteine zur Verfügung. Am wichtigsten sind zunächst regelmäßige Bewegung, angepasste Ernährung und ein normales Körpergewicht. Dies verbessert die Empfindlichkeit der Körperzellen für Insulin und kann so den Insulinbedarf senken. Zu Beginn der Therapie wird deshalb immer versucht, mit Allgemeinmaßnahmen, wie konsequente Lebensstiländerungen, auszukommen. Sind Allgemeinmaßnahmen nicht erfolgreich, stehen verschiedene Medikamente zur Verfügung, die zum Beispiel als Tabletten eingenommen werden können. Erst wenn es auch mit diesen Medikamenten nicht gelingt, die Erkrankung in den Griff zu bekommen, muss auch bei Typ-2 Diabetes Insulin gespritzt werden.
2025-03-17 21:40:49,217 - 250 - --------------------New Node ------------------------
2025-03-17 21:40:49,217 - 248 - ['Informationen zu Diabetes Typ 1 (gesund.bund.de) \uf110']
2025-03-17 21:40:49,217 - 249 - Hintergründe zu Ursachen, Symptomen, Verlauf und Behandlung uvm. finden Sie auf dem Gesundheitsportal des Bmg.
2025-03-17 21:40:49,217 - 250 - --------------------New Node ------------------------
2025-03-17 21:40:49,217 - 248 - ['Informationen zu Diabetes Typ 2 (gesund.bund.de) \uf110']
2025-03-17 21:40:49,217 - 249 - Hintergründe zu Ursachen, Symptomen, Verlauf und Behandlung uvm. finden Sie auf dem Gesundheitsportal des Bmg.
2025-03-17 21:40:49,217 - 250 - --------------------New Node ------------------------
2025-03-17 21:40:49,218 - 248 - ['Nationales Diabetesinformationsportal (diabinfo.de) \uf110']
2025-03-17 21:40:49,218 - 249 - Informationen zu Prävention, Therapie und Umgang mit allen Formen des Diabetes und assoziierter Erkrankungen wie Herz-Kreislauf-Erkrankungen.
2025-03-17 21:40:49,218 - 250 - --------------------New Node ------------------------
2025-03-17 21:40:49,218 - 248 - ['Diabetesnetz Deutschland \uf110']
2025-03-17 21:40:49,218 - 249 - Umsetzung der "Nationalen Aufklärungs-und Kommunikationsstrategie zu Diabetes mellitus
2025-03-17 21:40:49,218 - 250 - --------------------New Node ------------------------
2025-03-17 21:40:49,218 - 248 - ['Nationale Diabetes-Surveillance \uf110']
2025-03-17 21:40:49,218 - 249 - Ergebnisse der Surveillance und Informationen zum Vorhaben
2025-03-17 21:40:49,218 - 250 - --------------------New Node ------------------------
2025-03-17 21:40:49,218 - 248 - ['Deutsches Diabetes-Zentrum (DDZ) \uf110']
2025-03-17 21:40:49,218 - 249 - Hier gelangen Sie zur Seite des Deutschen Diabetes-Zentrums.
2025-03-17 21:40:49,218 - 250 - --------------------New Node ------------------------
2025-03-17 21:40:49,218 - 248 - ['Deutsches Zentrum für Diabetesforschung (DZD) \uf110']
2025-03-17 21:40:49,218 - 249 - Hier gelangen Sie zur Seite des Deutschen Zentrums für Diabetesforschung. Hintergründe zu Risikofaktoren, Folgen und Diagnose auf der Internetseite . Stand: November
```
**Current Behavior**: Despite `merge_peers=True`, short chunks like those above remain separate, possibly because their headings differ.
**Desired Outcome**: We’d like an option to merge these short chunks into a larger chunk, e.g., from “Hintergründe zu Ursachen...” to “Hier gelangen Sie zur Seite des Deutschen Zentrums für Diabetesforschung...”, as long as the total stays under `max_tokens`.
#### Our Setup
We use Docling as follows:
```python
extractor = SmartDocumentExtractor(verbose=settings.docling_settings.verbose)
docling_chunker = HybridChunker(tokenizer="SCAI-BIO/bio-gottbert-base", max_tokens=512)
docling_node_parser = DoclingNodeParser(chunker=docling_chunker)
documents = extractor.extract_documents(
str(temp_file_path),
quality_threshold=settings.docling_settings.quality_threshold
)
transformations = [docling_node_parser, DoclingCleaner(), embed_model]
pipeline = IngestionPipeline(
transformations=transformations,
vector_store=vector_store,
)
```
### Alternatives
1. **Post-Processing**: We could manually merge short chunks in our pipeline after `HybridChunker` runs by checking token counts and concatenating nodes with fewer than, say, 20 tokens into the previous chunk. However, this feels inefficient and duplicates logic that `HybridChunker` could handle natively.
2. **Adjust HierarchicalChunker**: Modify the underlying `HierarchicalChunker` to produce fewer small chunks, but this might disrupt the document structure we rely on, and we lack control over its internals.
3. **Disable `merge_peers` and Custom Logic**: Set `merge_peers=False` and implement our own merging strategy, but this loses the benefit of `HybridChunker`’s token-aware refinements.
None of these alternatives seem as elegant as enhancing `HybridChunker` with a `min_tokens` parameter to handle this natively.
### Additional Questions
- Does `merge_peers=True` already have a hidden minimum token threshold that we’re missing?
- Is there a way to tweak the current implementation to achieve this without a new parameter?
Thanks for considering this feature! It would greatly improve our use case with German medical texts.
Contributor guide
Assessment
This issue has not been assessed yet.