DocumentSetOperator
Persists a PyArrow table into a named DuckDB document set and passes the data through unchanged.
- Short Name:
document_set - Category: Storage
Overview
DocumentSetOperator stores pipeline data at rest in DuckDB using the docpipe document set
infrastructure. It uses a get-or-create pattern so re-running the same pipeline is safe
(idempotent). The operator returns the original table untouched, so it can be inserted at any
point in a pipeline without disrupting downstream operators.
Key Features
- Persistent columnar storage via DuckDB with automatic schema evolution
- Automatic metrics tracking (document count, size, page count)
- Upsert-based incremental updates keyed on
id - Pass-through design — input table is returned unchanged
- Idempotent: safe to re-run (get-or-create on
document_set_name) AttachmentRefcaptures adapter-specific storage coordinates and is managed independently of the document set metadata record
Operator Configuration
{
"type": "document_set",
"name": "store_documents",
"config": {
"document_set_name": "research_papers",
"description": "Processed research papers"
},
"depends_on": ["previous_operator"]
}
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
document_set_name |
string | Yes | — | Name of the document set to create or update |
description |
string | No | "" |
Human-readable description of the document set |
metadata |
object | No | {} |
Arbitrary JSON object stored as document set metadata |
document_set_id |
string | No | — | UUID of an existing document set to update instead of creating a new one |
database_path |
string | No | data/duckdb/document_sets.duckdb |
File path for the DuckDB database (metadata + data share this file) |
data_backend |
string | No | duckdb |
Data store backend for PyArrow table data. The metadata and attachment backend is configured separately via assets_management.document_set_repository.type in docling-pipelines-config.yaml. |
Output Columns
This operator does not add or remove columns. The original input table is returned unchanged.
Required input column:
| Column | Type | Description |
|---|---|---|
id |
string | Unique document identifier — used as the upsert key |
Examples
Example 1 — Basic storage
{
"type": "document_set",
"name": "store_docs",
"config": {
"document_set_name": "research_papers"
},
"depends_on": ["extract_step"]
}
Example 2 — With metadata and description
{
"type": "document_set",
"name": "store_financial_reports",
"config": {
"document_set_name": "financial_reports_q1_2024",
"description": "Quarterly financial reports for Q1 2024",
"metadata": {
"department": "finance",
"year": 2024,
"quarter": "Q1"
}
},
"depends_on": ["quality_check"]
}
Example 3 — Custom database path
{
"type": "document_set",
"name": "store_compliance_docs",
"config": {
"document_set_name": "compliance_documents",
"description": "Compliance documents",
"database_path": "./data/compliance.duckdb",
"metadata": {
"retention_policy": "7_years",
"compliance_standard": "SOX"
}
},
"depends_on": ["quality_check"]
}
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Error: Required column 'id' not found |
Input table is missing the id column |
Ensure DocIdHashOperator runs before this operator |
Error: Document set not found: <id> |
The UUID passed in document_set_id does not exist |
Verify the UUID, or omit document_set_id to create a new set |
Error: Invalid database path: Path traversal detected |
database_path contains .. segments |
Use an absolute path or a path relative to the workspace root |
Error: Cannot evolve schema: incompatible types |
A column's type changed between runs | Ensure upstream operators produce stable schemas, or recreate the document set |
| Duplicate documents accumulate across runs | Upsert requires a stable id per document |
Use DocIdHashOperator to generate deterministic IDs |
Architecture
Storage layers
DocumentSetOperator
└── DocumentSetService (application layer)
├── DataStoreFactory → DuckDBDocumentSetStorage
│ └── DuckDBTableStorage (columnar storage)
├── RepositoryFactory → DuckDBAssetRepository[DocumentSet]
│ └── DuckDBKeyValueStorage (document set registry)
└── AttachmentRepositoryFactory → DuckDBAttachmentRepository
└── DuckDBKeyValueStorage (attachment coordinates)
The data store adapter derives the physical table_name from the document set name (via
sanitize_table_name) and returns an AttachmentRef. The service persists that ref via the
AttachmentRepository, which stores it in a separate KV collection
(document_set_attachments). The metadata record and the attachment record have independent
lifecycles — storage coordinates are never embedded in the metadata record.
Pipeline placement
The operator is intentionally pass-through so it can be placed at multiple checkpoints:
Ingest → Extract → [DocumentSetOperator] → Quality → [DocumentSetOperator] → Chunk → Embed → VectorDB
Common placements:
- After extraction — store full document content before chunking
- After quality checks — store validated documents only
- Before indexing — create a recoverable checkpoint