Repository navigation
Apache Tika 4 Text Extraction
OpenCrawling leverages Apache Tika 4.1.0 as its enterprise-grade text extraction and document metadata parsing engine. Beginning in OpenCrawling 1.0.0, document text extraction is decoupled and executed using Tika's PipesForkParser, providing hard process isolation, watchdog timeouts, and memory bounds to protect crawler and worker runtimes from unhandled crashes, infinite loops, and Out-Of-Memory (OOM) errors.
Traditional document parsing in Java executes parsers (PDFBox, Apache POI, Commons Compress) in-process within the main application heap. In high-throughput enterprise crawling, this exposes worker containers to critical failure modes:
- Parser Hangs & Infinite Loops: Corrupted or adversarial documents can cause regex catastrophic backtracking or infinite loops inside deep parser stacks.
- Out-of-Memory (OOM) Errors: Decompression bombs (e.g., zip bombs) or massive rasterized PDFs can exhaust the container's heap, killing the entire worker or ingestion service.
-
JVM Segfaults: Native libraries or JNI bindings (e.g., font renderers, compression codecs) can crash the JVM outright without throwing a catchable Java
Exception. - Memory Leaks: Long-running workers accumulating uncollected parser cache buffers degrade performance over time.
OpenCrawling's PipesForkTextExtractor delegates document parsing to a dedicated, watchdog-monitored child JVM:
flowchart TD
subgraph HostWorker["OpenCrawling Host Worker (oc-runtime / IngestionConsumer)"]
Stream["Document Stream / Claim-Check"]
Service["TextExtractionService (PipesForkTextExtractor)"]
Watchdog["Timeout Watchdog Timer (30s)"]
end
subgraph ForkedJVM["Isolated Child Process (PipesServer JVM)"]
TikaCore["Apache Tika 4.1.0 Engine"]
Parsers["PDF, Office, HTML, OCR Parsers"]
end
Stream --> Service
Service -->|Pipes IPC / Stdio Discard| ForkedJVM
Watchdog -.->|Hard Kill on Timeout| ForkedJVM
ForkedJVM -->|TextExtractionResult & Metadata| Service
Service --> Chunks["Kafka Chunks Topic (opencrawling-chunks)"]
-
Hard Deadline Enforcement: If parsing exceeds
timeout-ms(default 30s), the watchdog forcibly terminates the child process (SIGKILL). The main worker survives and gracefully records a failure or falls back to plain-text recovery. -
Isolated Memory Bounds: The child process is constrained to its own heap via
jvm-args(e.g.,-Xmx512m), ensuring heap exhaustion never impacts host services. -
Process Recycling: After parsing a configurable number of files (
max-files-per-process, default 10,000), the child process is automatically recycled to prevent slow native memory leaks. - Graceful In-Process Fallback: If process isolation is disabled or fails to initialize on constrained architectures, the system automatically falls back to embedded in-process Tika extraction.
The text extraction subsystem is centralized in oc-core and exposed through standard Spring Boot auto-configuration:
-
TextExtractionService: The high-level SPI for text extraction, accepting documentbyte[]arrays orInputStreamwith initial metadata (such asmimeTypeandfilename). -
PipesForkTextExtractor: The primary implementation orchestratingPipesForkParser, process watchdog monitoring, and library discovery. -
TextExtractionProperties: Spring Boot@ConfigurationProperties(prefix = "opencrawling.tika")binding all extraction parameters. -
TextExtractionResult: Encapsulates extracted text, merged metadata, truncation flags, and error messages.
All 9 OpenCrawling output connectors consume the centralized TextExtractionService instead of bundling individual Tika dependencies:
-
oc-luxir-output-connector(Luxir Search Engine) -
oc-milvus-output-connector(Milvus Vector DB) -
oc-opensearch2-output-connector(OpenSearch 2.x) -
oc-opensearch3-output-connector(OpenSearch 3.x) -
oc-qdrant-output-connector(Qdrant Vector DB) -
oc-seatunnel-output-connector(Apache SeaTunnel) -
oc-solr-output-connector(Apache Solr) -
oc-vector-output-connector(PostgreSQL pgvector) -
oc-vespa-output-connector(Vespa Engine)
Because PipesForkParser spawns a standalone child JVM process (java -cp ... org.apache.tika.pipes.PipesServer), all Tika parsers and third-party dependencies must be accessible on the child classpath.
OpenCrawling Docker images (Dockerfile.crawler, Dockerfile.ingestion-consumer, Dockerfile.writer-consumer, and oc-runtime/Dockerfile) leverage Spring Boot jar extraction:
# Extract the fat jar into thin application jar and isolated libraries
RUN java -Djarmode=tools -jar app.jar extract --destination /app/extracted
# Copy dependencies to /app/lib
COPY --from=builder /app/extracted/lib ./lib
COPY --from=builder /app/extracted/oc-runtime-1.0.0-SNAPSHOT.jar app.jar
ENV TIKA_EXTRAS_DIR=/app/lib
ENTRYPOINT ["java", "-Dtika.extras.dir=/app/lib", "-jar", "app.jar"]When launching the child process, PipesForkTextExtractor resolves tika.extras.dir using the following order of precedence:
-
System Property:
-Dtika.extras.dir=/path/to/lib -
Environment Variable:
TIKA_EXTRAS_DIR=/path/to/lib -
Standard Layout Paths: Checks
./liband/app/lib -
Sibling Lib Directory: Discovers
../librelative to the executing JAR -
Fat-Jar Extraction Fallback: If running from an unextracted Spring Boot uber JAR in development, it extracts
BOOT-INF/lib/*.jarinto a temporary directory (/tmp/opencrawling-tika-fork-libs) with built-in Zip Slip protection (CWE-022).
When unpacking JARs or archives, PipesForkTextExtractor enforces strict Zip Slip path traversal defenses:
- Rejects any archive entry whose name contains
..path traversal sequences. - Normalizes destination paths using
toAbsolutePath().normalize(). - Verifies that the resolved target path begins with the destination directory boundary (
outFile.startsWith(destinationDir)), throwing aSecurityExceptionupon any escape attempt. - Automatically strips ASCII null bytes (
\u0000) from extracted text to prevent UTF-8 database insertion errors in PostgreSQL (pgvector).
opencrawling:
tika:
enabled: true # Enable or disable text extraction
fork-enabled: true # Enable PipesForkParser process isolation
timeout-ms: 30000 # Hard deadline per document (30s)
write-limit: 20000000 # Max characters extracted (20M)
num-clients: 1 # Parallel forked client processes
max-files-per-process: 10000 # Recycle child process after N documents
extract-embedded: false # Extract embedded documents/attachments
jvm-args:
- "-Xmx512m" # Child JVM heap limit| Environment Variable | Spring Property | Default | Description |
|---|---|---|---|
OPENCRAWLING_TIKA_ENABLED |
opencrawling.tika.enabled |
true |
Master switch for text extraction |
OPENCRAWLING_TIKA_FORK_ENABLED |
opencrawling.tika.fork-enabled |
true |
Enable process-isolated fork parsing |
OPENCRAWLING_TIKA_TIMEOUT_MS |
opencrawling.tika.timeout-ms |
30000 |
Hard watchdog timeout in milliseconds |
OPENCRAWLING_TIKA_WRITE_LIMIT |
opencrawling.tika.write-limit |
20000000 |
Max character extraction limit (-1 for unlimited) |
OPENCRAWLING_TIKA_NUM_CLIENTS |
opencrawling.tika.num-clients |
1 |
Number of concurrent forked client workers |
OPENCRAWLING_TIKA_MAX_FILES_PER_PROCESS |
opencrawling.tika.max-files-per-process |
10000 |
Process recycling threshold |
OPENCRAWLING_TIKA_EXTRACT_EMBEDDED |
opencrawling.tika.extract-embedded |
false |
Recursively extract embedded attachments |
OPENCRAWLING_TIKA_JVM_ARGS |
opencrawling.tika.jvm-args |
-Xmx512m |
Memory and JVM parameters for child processes |
TIKA_EXTRAS_DIR |
tika.extras.dir |
/app/lib |
Directory path containing extra parser JARs |
Administrators can inspect and manage Tika process isolation directly from oc-admin-ui:
-
Dashboard Indicator: Displays the active text extraction engine:
-
PipesForkParser (Process-Isolated): Child JVM watchdog monitoring is active. -
In-Process Embedded Tika: Direct in-memory parsing is active.
-
-
Settings Panel -> Text Extraction (Tika):
- Toggle between PipesForkParser and Embedded In-Process Tika.
- Adjust Watchdog Timeout slider (5s – 120s).
- Configure Forked JVM Heap Limit (
-Xmx256m,-Xmx512m,-Xmx1024m,-Xmx2048m, or custom). - Set Process Recycling Threshold and Character Write Limits.
- Toggle Embedded Attachment Extraction.
Run the core text extraction unit test suite to verify fork isolation, fallback, and archive security:
mvn test -pl oc-core -Dtest=PipesForkTextExtractorTestExpected output:
[INFO] Running org.opencrawling.core.text.PipesForkTextExtractorTest
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
- Home
- User & Installation Guide
- Quick Start
- VM & Bare-Metal Distribution Installation
- Local Development & Fast Docker Builds
- User Guide
- Architecture
- Zero-Trust Security & ACL Management
- Document Lifecycle Actions & Tombstones
- Apache Tika 4 Text Extraction
- Configuration Guide
- Connectors Reference
- Alfresco Content Services (ACS) Connector
- Alfresco Process Services (APS) Connector
- Flowable Repository Connector
- Camunda Repository Connector
- OASIS CMIS Repository Connector
- Doxis Repository Connector
- M-Files Repository Connector
- SharePoint Online Repository Connector
- Hyland OpenArch Integration (Repository, Output & MCP)
- Relational Database (JDBC) Connector
- Apache StormCrawler Repository Connector
- gRPC Push Repository Connector
- Apache Solr Output Connector
- Luxir Output Connector
- Apache SeaTunnel Output Connector
- Apache Ozone Output Connector (Migration Mode)
- Connector Execution Modes
- Model Context Protocol
- Apache Ozone Claim Check Store
- Lakehouse Audit Reporting & Ledger
- AI-Powered Observability (AIOps)
- Auto-Narrativization Copilot
- Maven Connector Archetypes
- Java Client SDK
- OpenCrawling CLI
- OpenAPI Specification & Swagger UI
- gRPC Internal Transport
- Migration Guide (ManifoldCF)
- Integration Test — Decoupled Pipeline
- M-Files Integration Test
- SharePoint Online Integration Test
- Hyland OpenArch Integration Test
- Local Docker Build Test
- Secure MCP Server Integration Test
- Narrativization Integration Test
- Reporting Integration Test