Connectors - opencrawling/opencrawling GitHub Wiki
OpenCrawling is built around a connector-based architecture. Every step of the pipeline — ingesting content from a source, transforming it via embeddings, and writing it to a destination — is handled by a dedicated connector implementing a well-defined Java interface.
| Type | Interface | Role |
|---|---|---|
| Repository Connector | RepositoryConnector |
Scans a content source and emits RepositoryDocument objects as a reactive Flux stream |
| Output Connector | OutputConnector |
Receives a RepositoryDocument and writes it directly to a destination (sync/direct mode) |
| Transformation Connector | Configured via Admin UI | Selects the embedding engine (Ollama, OpenAI, etc.) for the oc-embedding-service
|
RepositoryConnector (in oc-core):
public non-sealed interface RepositoryConnector extends Connector {
Flux<RepositoryDocument> scan(String basePath);
}OutputConnector (in oc-core):
public non-sealed interface OutputConnector extends Connector {
Mono<Void> send(RepositoryDocument document);
}Both extend Connector which provides getName(), connect(), and disconnect() lifecycle methods.
Repository connectors are responsible for discovering and streaming documents from content sources into the pipeline.
Module: oc-filesystem-repository-connector
Class: FileSystemRepositoryConnector
Spring Bean: @Primary — selected by default when no other connector is specified
Recursively scans a local filesystem directory using Java NIO and emits each regular file as a RepositoryDocument. Subdirectory traversal is parallelised using Java 25 Structured Task Scope for high-throughput I/O on deep directory trees.
No external configuration properties are required. The path is provided at runtime via the scan(String basePath) call (e.g., from the Admin UI job form or the crawler SCAN_PATH environment variable).
| Metadata key | Value |
|---|---|
extension |
File extension (e.g. pdf, txt, docx) |
uri |
file:// URI of the absolute path |
Set the connector type to filesystem in the Admin UI or via the environment variable:
# docker-compose-decoupled.yml
environment:
CONNECTOR_TYPE: filesystem
SCAN_PATH: /data- Files are streamed; content is not loaded into memory until processed.
- The
uriis afile://URI (e.g.file:///data/report.pdf), so no Claim Check Pattern is used — theIngestionConsumerreads directly from the local filesystem path.
Module: oc-alfresco-repository-connector
Class: AlfrescoRepositoryConnector
Security Mapper: AlfrescoSecurityMapper
Spring Bean: @Component (activated when CONNECTOR_TYPE=alfresco or spring.opencrawling.connector.type=alfresco)
Dedicated Guide: Alfresco Content Services (ACS) Connector
Connects to an Alfresco Content Services (Community or Enterprise) instance via the native Alfresco Core REST API v1 and Alfresco Search REST API v1. Supports dual-mode ingestion:
-
Hierarchical Folder Tree Traversal: Scans from root (
-root-), a specific folder path (e.g./Company Home/Sites), a Node UUID, or a site document library (siteId), with options to toggle subfolder recursion (includeSubfolders) and exclude specific folders (excludedFolders). -
Search API Query Ingestion: Executes declarative AFTS (Alfresco Full Text Search), CMIS SQL, or Lucene queries against
/public/search/versions/1/search.
Features zero-trust ACL mapping via AlfrescoSecurityMapper (extracting inherited and locally set permissions for users and GROUP_* authorities), binary content stream size thresholds (maxContentSizeBytes), and metadata-only indexing (includeContentStream=false).
| Property key | Spring property | Environment variable | Default | Description |
|---|---|---|---|---|
url |
spring.opencrawling.connector.alfresco.url |
ALFRESCO_URL |
http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1 |
Base URL of the Alfresco REST API |
username |
spring.opencrawling.connector.alfresco.username |
ALFRESCO_USERNAME |
admin |
Alfresco username |
password |
spring.opencrawling.connector.alfresco.password |
ALFRESCO_PASSWORD |
admin |
Alfresco password (Basic Auth) |
batchSize |
spring.opencrawling.connector.alfresco.batch-size |
ALFRESCO_BATCH_SIZE |
100 |
Number of items fetched per API page |
crawlMode |
spring.opencrawling.connector.alfresco.crawl-mode |
ALFRESCO_CRAWL_MODE |
folder |
Ingestion mode: folder or query
|
queryLanguage |
spring.opencrawling.connector.alfresco.query-language |
ALFRESCO_QUERY_LANGUAGE |
afts |
Query language: afts, cmis, or lucene
|
searchQuery |
spring.opencrawling.connector.alfresco.search-query |
ALFRESCO_SEARCH_QUERY |
TYPE:'cm:content' |
Default query for query crawl mode |
rootFolderPath |
spring.opencrawling.connector.alfresco.root-folder-path |
ALFRESCO_ROOT_FOLDER_PATH |
/ |
Default folder path to scan |
rootFolderId |
spring.opencrawling.connector.alfresco.root-folder-id |
ALFRESCO_ROOT_FOLDER_ID |
"" |
Optional starting node UUID |
siteId |
spring.opencrawling.connector.alfresco.site-id |
ALFRESCO_SITE_ID |
"" |
Optional Site ID (auto-targets documentLibrary) |
includeSubfolders |
spring.opencrawling.connector.alfresco.include-subfolders |
ALFRESCO_INCLUDE_SUBFOLDERS |
true |
Recursively traverse child folders |
excludedFolders |
spring.opencrawling.connector.alfresco.excluded-folders |
ALFRESCO_EXCLUDED_FOLDERS |
Data Dictionary |
Comma-separated folder names/paths to skip |
includeAcls |
spring.opencrawling.connector.alfresco.include-acls |
ALFRESCO_INCLUDE_ACLS |
true |
Extract ACE permissions and zero-trust ACLs |
includeContentStream |
spring.opencrawling.connector.alfresco.include-content-stream |
ALFRESCO_INCLUDE_CONTENT_STREAM |
true |
Download binary payload for text extraction |
maxContentSizeBytes |
spring.opencrawling.connector.alfresco.max-content-size-bytes |
ALFRESCO_MAX_CONTENT_SIZE_BYTES |
52428800 |
Max payload size in bytes (50 MB) |
mimeTypeFilter |
spring.opencrawling.connector.alfresco.mimetype-filter |
ALFRESCO_MIMETYPE_FILTER |
"" |
Comma-separated MIME whitelist (e.g. application/pdf) |
oc-crawler:
environment:
CONNECTOR_TYPE: alfresco
SCAN_PATH: /Company Home
ALFRESCO_URL: http://alfresco:8080/alfresco/api/-default-/public/alfresco/versions/1
ALFRESCO_USERNAME: admin
ALFRESCO_PASSWORD: admin
ALFRESCO_CRAWL_MODE: folder
ALFRESCO_INCLUDE_SUBFOLDERS: "true"
ALFRESCO_INCLUDE_ACLS: "true"| Format | Behaviour |
|---|---|
(empty) or -root-
|
Scans from the Alfresco repository root |
/Company Home/Sites/my-site |
Scans using a relative path from root |
a1b2c3d4-... (UUID) |
Scans a specific node by its Alfresco Node ID |
TYPE:'cm:content' AND PATH:'/app:company_home//*' |
Executes AFTS query via Search REST API |
SELECT * FROM cmis:document WHERE cmis:name LIKE 'Invoice%' |
Executes CMIS SQL query via Search REST API |
| Metadata key | Value source |
|---|---|
name |
entry.name from the API response |
nodeType |
entry.nodeType (e.g. cm:content) |
mimeType |
entry.content.mimeType |
sizeInBytes |
entry.content.sizeInBytes |
alfresco_node_id |
Alfresco node UUID |
alfresco_parent_id |
Parent folder UUID |
alfresco_aspects |
Attached aspect names |
alfresco_identity_users |
Comma-separated authorized reader users |
alfresco_identity_groups |
Comma-separated authorized reader groups |
alfresco_is_inherited |
Boolean flag for permission inheritance |
cm:title, cm:description, etc. |
All Alfresco cm:* properties returned via ?include=properties
|
Because Alfresco documents are fetched from a remote HTTP server, the connector downloads the content stream and saves it to a local shared directory (/data/claims/) before publishing the reference to Kafka. This decouples the slow HTTP download from the fast Kafka publish step.
Note
The shared /data directory must be volume-mounted and accessible by both the crawler and the consumer containers in the decoupled deployment.
After a crawl job completes, verify ingestion with:
-- Total chunks stored for Alfresco documents
SELECT count(*) FROM vector_store_1024;
-- Inspect content and source URI of stored chunks
SELECT id,
LEFT(content, 200) AS preview,
metadata->>'name' AS filename,
metadata->>'mimeType' AS mime_type,
metadata->>'uri' AS source_uri
FROM vector_store_1024
ORDER BY id
LIMIT 10;
-- Semantic similarity search
SELECT id,
LEFT(content, 300) AS preview,
metadata->>'name' AS filename,
1 - (embedding <=> (
SELECT embedding FROM vector_store_1024 LIMIT 1
)) AS similarity
FROM vector_store_1024
ORDER BY similarity DESC
LIMIT 5;Module: oc-iceberg-repository-connector
Class: IcebergRepositoryConnector
Spring Bean: @Component (activated when CONNECTOR_TYPE=iceberg)
Connects to an Apache Iceberg table catalog and scans structured data tables, emitting each Iceberg Record as a JSON-serialized RepositoryDocument. Supports REST, Hive Metastore, Hadoop, AWS Glue, and in-memory catalog backends. File scan tasks are parallelized using Java 25 Structured Task Scope for high-throughput Parquet file reading.
Each record is serialized to JSON and treated as a document, making Iceberg data lakes a first-class ingestion source for RAG pipelines. This connector reads Parquet data files directly from the catalog's underlying storage (local FS, S3, GCS, ADLS, etc.).
| Property key | Default | Description |
|---|---|---|
catalogType |
in-memory |
Catalog backend type: rest, hive, hadoop, glue, or in-memory
|
catalogUri |
(empty) | URI of the catalog server (required for rest and hive types) |
warehouse |
tmp/iceberg-warehouse |
Warehouse root path (local path, s3://, gs://, abfs://, etc.) |
idColumn |
(empty) | Optional column name to use as the document ID. Falls back to Iceberg identifier fields, then SHA-256 of JSON content |
catalogType |
Implementation | Required catalogUri
|
|---|---|---|
rest |
RESTCatalog |
REST catalog server URL (e.g. http://localhost:8181) |
hive |
HiveCatalog |
Hive Metastore Thrift URI (e.g. thrift://hive:9083) |
hadoop |
HadoopCatalog |
Not required — uses warehouse path directly |
glue |
GlueCatalog (via reflection) |
Not required — uses AWS SDK credentials chain |
in-memory |
InMemoryCatalog |
Not required — ephemeral, for testing only |
Module: oc-flowable-repository-connector
Class: FlowableRepositoryConnector
Security Mapper: FlowableSecurityMapper
Spring Bean: @Component (activated when CONNECTOR_TYPE=flowable or spring.opencrawling.connector.type=flowable)
Dedicated Guide: Flowable Repository Connector
Connects to a Flowable BPMN Engine REST service (/history/historic-process-instances) to crawl completed and active historic workflow executions, structure process details, extract BPMN variables (/history/historic-variable-instances), and resolve runtime/historic identity links (/history/historic-process-instances/{id}/identitylinks).
Process instances are emitted as standard RepositoryDocument instances containing structured JSON summaries (definition key, business key, start/end timestamps, duration, and user ID), entity reference links, and fine-grained SecurityConfig permissions.
The connector supports two zero-trust architectural models:
-
Collocated DB Pattern (pgvector on Flowable PostgreSQL): Entity references (
flowable_proc_inst_id,flowable_scope_id,flowable_scope_type) are stamped to allow query-time SQLEXISTSsubqueries against nativeACT_RU_IDENTITYLINKandACT_HI_IDENTITYLINKtables, eliminating distributed transaction lag without chunk-level row multiplication. -
Distributed DB Pattern (External Vector DBs): Extracts user and candidate group identity links into standard OIS
security_allowed_readmetadata fields for pre-filtering in Qdrant, Milvus, OpenSearch, and Vespa.
Batch scanning and variable resolution are parallelized using Java 25 Structured Task Scope and Virtual Threads (Thread.ofVirtual()).
| Property key | Spring Property Key | Default | Description |
|---|---|---|---|
url |
spring.opencrawling.connector.flowable.url |
http://localhost:8080/flowable-rest/service |
Flowable REST API endpoint |
username |
spring.opencrawling.connector.flowable.username |
admin |
Basic auth username |
password |
spring.opencrawling.connector.flowable.password |
test |
Basic auth password |
batchSize |
spring.opencrawling.connector.flowable.batch-size |
100 |
Number of process instances per page |
processDefinitionKey |
spring.opencrawling.connector.flowable.process-definition-key |
"" |
Optional process definition key filter |
includeVariables |
spring.opencrawling.connector.flowable.include-variables |
true |
Extract historic BPMN process variables |
includeAcls |
spring.opencrawling.connector.flowable.include-acls |
true |
Extract identity links and map to SecurityConfig |
scope |
spring.opencrawling.connector.flowable.scope |
all |
Filter by state: all, completed, or active
|
| Format | Behaviour |
|---|---|
(empty) or /
|
Scans all historic process instances |
invoice-process |
Scans process instances matching process definition key invoice-process
|
| Metadata key | Description |
|---|---|
processDefinitionId |
Flowable Process Definition ID (e.g. invoice-process:2:98765) |
processDefinitionKey |
Flowable Process Definition Key (e.g. invoice-process) |
businessKey |
Workflow business key (e.g. INV-2026-001) |
startUserId |
User ID that started the process instance |
startTime |
Workflow execution start timestamp |
endTime |
Workflow completion timestamp |
durationInMillis |
Workflow execution duration in milliseconds |
flowable_proc_inst_id |
Flowable Process Instance ID for collocated entity linking |
flowable_scope_id |
Flowable Scope ID (processInstanceId) |
flowable_scope_type |
Flowable Scope Type ("processInstance") |
flowable_identity_users |
List of authorized user IDs resolved from identity links |
flowable_identity_groups |
List of authorized candidate group IDs resolved from identity links |
flowable_var_<varName> |
Dynamically mapped historical BPMN process variable value |
{
"id": "proc-1234",
"uri": "flowable://process-instances/proc-1234",
"action": "UPSERT",
"metadata": {
"mimeType": ["application/json"],
"processDefinitionId": ["invoice-process:2:98765"],
"processDefinitionKey": ["invoice-process"],
"businessKey": ["INV-2026-001"],
"startUserId": ["finance_agent_1"],
"startTime": ["2026-07-23T08:00:00Z"],
"endTime": ["2026-07-23T08:15:00Z"],
"durationInMillis": ["900000"],
"flowable_proc_inst_id": ["proc-1234"],
"flowable_process_instance_id": ["proc-1234"],
"flowable_scope_id": ["proc-1234"],
"flowable_scope_type": ["processInstance"],
"flowable_identity_users": ["finance_agent_1"],
"flowable_identity_groups": ["finance_managers"],
"flowable_var_totalAmount": ["250.50"],
"flowable_var_customerName": ["ACME Corp"]
},
"security": {
"inheritanceEnabled": false,
"permissions": [
{"identity": "finance_agent_1", "identityType": "user", "access": "read"},
{"identity": "finance_managers", "identityType": "group", "access": "read"}
]
}
}Module: oc-camunda-repository-connector
Class: CamundaRepositoryConnector
Security Mapper: CamundaSecurityMapper
Spring Bean: @Component (activated when CONNECTOR_TYPE=camunda or spring.opencrawling.connector.type=camunda)
Dedicated Guide: Camunda Repository Connector
Connects to a Camunda Platform 7 REST Engine (/engine-rest/history/process-instance) to crawl historic workflow executions, process instance details, historical BPMN process variables (/history/variable-instance), and historic identity link authorizations (/history/identity-link-log).
Process instances are emitted as standard RepositoryDocument instances containing structured JSON summaries (definition key, business key, start/end timestamps, duration, and start user ID), entity reference links, and fine-grained SecurityConfig permissions.
The connector supports two zero-trust architectural models:
-
Collocated DB Pattern (pgvector on Camunda PostgreSQL): Entity references (
camunda_proc_inst_id,camunda_scope_id,camunda_scope_type) are stamped to allow query-time SQLEXISTSsubqueries against nativeACT_RU_IDENTITYLINKandACT_HI_IDENTITYLINKtables, eliminating distributed transaction lag without chunk-level row multiplication. -
Distributed DB Pattern (External Vector DBs): Extracts user and candidate group identity links into standard OIS
security_allowed_readmetadata fields for pre-filtering in Qdrant, Milvus, OpenSearch, and Vespa.
Batch scanning and variable resolution are parallelized using Java 25 Structured Task Scope and Virtual Threads (Thread.ofVirtual()).
| Property key | Spring Property Key | Default | Description |
|---|---|---|---|
url |
spring.opencrawling.connector.camunda.url |
http://localhost:8080/engine-rest |
Camunda REST API endpoint |
username |
spring.opencrawling.connector.camunda.username |
demo |
Basic auth username |
password |
spring.opencrawling.connector.camunda.password |
demo |
Basic auth password |
batchSize |
spring.opencrawling.connector.camunda.batch-size |
100 |
Number of process instances per page |
processDefinitionKey |
spring.opencrawling.connector.camunda.process-definition-key |
"" |
Optional process definition key filter |
includeVariables |
spring.opencrawling.connector.camunda.include-variables |
true |
Extract historic BPMN process variables |
includeAcls |
spring.opencrawling.connector.camunda.include-acls |
true |
Extract identity links and map to SecurityConfig |
scope |
spring.opencrawling.connector.camunda.scope |
all |
Filter by state: all, completed, or active
|
| Format | Behaviour |
|---|---|
(empty) or /
|
Scans all historic process instances |
order-process |
Scans process instances matching process definition key order-process
|
| Metadata key | Description |
|---|---|
processDefinitionId |
Camunda Process Definition ID (e.g. order-process:1:1001) |
processDefinitionKey |
Camunda Process Definition Key (e.g. order-process) |
businessKey |
Workflow business key (e.g. ORD-2026-999) |
startUserId |
User ID that started the process instance |
startTime |
Workflow execution start timestamp |
endTime |
Workflow completion timestamp |
durationInMillis |
Workflow execution duration in milliseconds |
tenantId |
Multi-tenant identifier (if applicable) |
camunda_proc_inst_id |
Native Process Instance ID for collocated DB joins |
camunda_scope_id |
Engine scope identifier for entity-level authorization |
camunda_scope_type |
Scope type identifier (processInstance) |
camunda_identity_users |
List of allowed user identities |
camunda_identity_groups |
List of allowed group identities |
camunda_var_<varName> |
Dynamically mapped historical BPMN process variable value |
{
"id": "proc-9988",
"uri": "camunda://process-instances/proc-9988",
"action": "UPSERT",
"metadata": {
"mimeType": ["application/json"],
"processDefinitionId": ["order-process:1:1001"],
"processDefinitionKey": ["order-process"],
"businessKey": ["ORD-2026-999"],
"startUserId": ["sales_rep_42"],
"startTime": ["2026-07-24T10:00:00Z"],
"endTime": ["2026-07-24T10:05:00Z"],
"durationInMillis": ["300000"],
"tenantId": ["tenant-alpha"],
"camunda_proc_inst_id": ["proc-9988"],
"camunda_process_instance_id": ["proc-9988"],
"camunda_scope_id": ["proc-9988"],
"camunda_scope_type": ["processInstance"],
"camunda_identity_users": ["sales_rep_42", "approver_1"],
"camunda_identity_groups": ["finance-managers"],
"camunda_var_orderAmount": ["1500.00"],
"camunda_var_approvalStatus": ["APPROVED"]
},
"security": {
"inheritanceEnabled": false,
"permissions": [
{"identity": "sales_rep_42", "identityType": "user", "access": "read"},
{"identity": "approver_1", "identityType": "user", "access": "read"},
{"identity": "finance-managers", "identityType": "group", "access": "read"}
]
}
}The basePath argument to scan() is an Iceberg table identifier in the format <namespace>.<table>:
| Format | Example | Description |
|---|---|---|
namespace.table |
analytics.events |
Scans the events table in the analytics namespace |
db.schema.table |
prod.dbo.orders |
Three-part identifier (catalog-specific) |
| Metadata key | Value |
|---|---|
| All Iceberg record columns | Included as metadata entries (column name → string value) |
mimeType |
Always application/json
|
sizeInBytes |
Size of the JSON-serialized record in bytes |
uri |
iceberg://<table-name>/<document-id> |
The document ID is resolved in order of priority:
- The column specified in
idColumnconfig property - Iceberg table's declared identifier fields
- SHA-256 hash of the JSON record content (fallback)
Use the dedicated compose file provided in the oc-iceberg-repository-connector module to spin up a local Iceberg REST catalog backed by MinIO (S3-compatible object storage):
# oc-iceberg-repository-connector/docker-compose.yml
services:
minio:
image: minio/minio:RELEASE.2024-05-10T01-39-19Z
container_name: minio-iceberg
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: password
ports:
- "9000:9000"
- "9001:9001"
command: ["server", "/data", "--console-address", ":9001"]
iceberg-rest:
image: apache/iceberg-rest-fixture:1.5.0
container_name: iceberg-rest
ports:
- "8181:8181"
environment:
- AWS_ACCESS_KEY_ID=admin
- AWS_SECRET_ACCESS_KEY=password
- AWS_REGION=us-east-1
- CATALOG_WAREHOUSE=s3://warehouse/
- CATALOG_IO__IMPL=org.apache.iceberg.aws.s3.S3FileIO
- CATALOG_S3_ENDPOINT=http://minio:9000
- CATALOG_S3_PATH_STYLE_ACCESS=true
depends_on:
- minioThen configure the crawler to use this catalog:
oc-crawler:
environment:
CONNECTOR_TYPE: iceberg
SCAN_PATH: analytics.events
ICEBERG_CATALOG_TYPE: rest
ICEBERG_CATALOG_URI: http://iceberg-rest:8181
ICEBERG_WAREHOUSE: s3://warehouse/- The connector does not use the Claim Check Pattern — Iceberg records are serialized to JSON in-process and streamed directly as
RepositoryDocumentobjects. No shared volume is required. - The
urifield uses aniceberg://scheme that identifies the source table and record ID. - For timestamp-based last-modified detection, the connector inspects well-known column names:
last_modified,updated_at,timestamp, anddate. - AWS Glue catalog requires the
iceberg-awsdependency on the classpath and AWS credentials configured via environment variables or instance profile.
Module: oc-stormcrawler-repository-connector (with oc-stormcrawler-bolt)
Class: StormCrawlerRepositoryConnector
Spring Bean: @Component (activated when CONNECTOR_TYPE=stormcrawler)
Dedicated Guide: Apache StormCrawler Repository Connector & OpenCrawling Bolt
Orchestrates, monitors, and streams distributed web crawls using Apache StormCrawler 3.7.0 running on Apache Storm 3.1.0 clusters and Java 25.
The connector interacts with the Apache Storm Nimbus REST API to verify cluster health (/api/v1/cluster/summary) and manage topology states (/api/v1/topology/summary). For distributed worker processing, the accompanying OpenCrawlingBolt intercepts parsed HTML content and deletion status streams (HTTP 404/410), normalising them into Open Ingestion Standard (OIS) UPSERT and DELETE payloads dispatched to OpenCrawling.
High-throughput seed scanning and URL resolution leverage Java 25 Virtual Threads and StructuredTaskScope.
| Property key | Spring Property Key | Default | Description |
|---|---|---|---|
nimbusHost |
spring.opencrawling.connector.stormcrawler.nimbus-host |
localhost |
Apache Storm Nimbus hostname |
nimbusPort |
spring.opencrawling.connector.stormcrawler.nimbus-port |
6627 |
Nimbus Thrift RPC port |
nimbusRestUrl |
spring.opencrawling.connector.stormcrawler.nimbus-rest-url |
http://localhost:8080 |
Storm UI / Nimbus REST API base URL |
topologyName |
spring.opencrawling.connector.stormcrawler.topology-name |
opencrawling-web-crawler |
Target StormCrawler topology name |
seeds |
spring.opencrawling.connector.stormcrawler.seeds |
https://docs.example.com |
Comma-separated seed URLs to crawl |
concurrency |
spring.opencrawling.connector.stormcrawler.concurrency |
8 |
Parallel virtual threads for crawl tasks |
delayMs |
spring.opencrawling.connector.stormcrawler.delay-ms |
1000 |
Politeness delay between requests in milliseconds |
ignoreRobotsTxt |
spring.opencrawling.connector.stormcrawler.ignore-robots-txt |
false |
Whether to ignore robots.txt disallow directives |
customUserAgent |
spring.opencrawling.connector.stormcrawler.custom-user-agent |
OpenCrawling-StormCrawler-Bot/1.0 |
Custom User-Agent header |
| Metadata key | Description |
|---|---|
title |
Page <title> extracted from HTML |
parse.Content-Type |
MIME type (e.g. text/html) |
http.status |
HTTP response code (e.g. 200) |
canonical.url |
Canonical URL resolved from <link rel="canonical"> or HTTP headers |
content.hash |
Cryptographic hash (SHA-256 or MD5) for deduplication |
uri |
URL of the crawled web page |
# docker-compose-decoupled-with-stormcrawler.yml
services:
oc-crawler:
environment:
CONNECTOR_TYPE: stormcrawler
STORMCRAWLER_NIMBUS_HOST: storm-nimbus
STORMCRAWLER_NIMBUS_REST_URL: http://storm-ui:8080
STORMCRAWLER_TOPOLOGY_NAME: opencrawling-web-crawler
STORMCRAWLER_SEEDS: https://docs.opencrawling.orgModule: oc-aps-repository-connector
Class: ApsRepositoryConnector (with ApsMcpClient)
Spring Bean: @Component (activated when CONNECTOR_TYPE=aps)
Dedicated Guide: Alfresco Process Services (APS) Repository Connector
Connects to Alfresco Process Services (APS) 26.2 via the Enterprise REST API (/activiti-app/api/enterprise) to crawl historic and active process executions (/historic-process-instances/query), dynamically extract all process variables (/historic-process-instances/{id}/variables), and evaluate user tasks and candidate group authorizations (/tasks/query).
In addition to workflow execution metrics, the connector features Workflow Attachment Ingestion: it discovers documents and text attachments attached at the process instance level or task level (/content/{contentId}/raw), streams them into the Claim-Check store, extracts text with Apache Tika, and links them to the parent workflow with inherited variables and Zero-Trust Access Control Lists (ACLs).
The connector supports two zero-trust architectural models:
-
Collocated DB Pattern (pgvector on APS PostgreSQL): Entity references (
aps_proc_inst_id,aps_scope_id,aps_scope_type) are stamped to allow query-time SQLEXISTSsubqueries against nativeACT_RU_IDENTITYLINKandACT_HI_IDENTITYLINKtables, eliminating distributed transaction lag without chunk-level row multiplication. -
Distributed DB Pattern (External Vector DBs): Extracts user and candidate group identity links into standard OIS
security_allowed_readmetadata fields for pre-filtering in Qdrant, Milvus, OpenSearch, and Vespa.
The connector also provides an ApsMcpClient to dynamically discover deployed workflow definitions and schema metadata via the Model Context Protocol (MCP). Batch processing is parallelized using Java 25 Virtual Threads and StructuredTaskScope.
| Property key | Spring Property Key | Default | Description |
|---|---|---|---|
url |
spring.opencrawling.connector.aps.url |
http://localhost:8080/activiti-app/api/enterprise |
Base URL of the APS Enterprise REST API |
username |
spring.opencrawling.connector.aps.username |
[email protected] |
APS Basic Auth username |
password |
spring.opencrawling.connector.aps.password |
admin |
APS Basic Auth password |
batchSize |
spring.opencrawling.connector.aps.batch-size |
100 |
Process instance page batch size |
processDefinitionKey |
spring.opencrawling.connector.aps.process-definition-key |
"" |
Optional process definition key filter |
includeVariables |
spring.opencrawling.connector.aps.include-variables |
true |
Ingest process instance variables |
includeTasks |
spring.opencrawling.connector.aps.include-tasks |
true |
Ingest user tasks |
includeAttachments |
spring.opencrawling.connector.aps.include-attachments |
true |
Ingest workflow attachments & documents |
includeAcls |
spring.opencrawling.connector.aps.include-acls |
true |
Extract task assignees and candidate groups into SecurityConfig |
tenantId |
spring.opencrawling.connector.aps.tenant-id |
"" |
Optional tenant ID for multi-tenant APS |
scope |
spring.opencrawling.connector.aps.scope |
all |
Filter by state: all, active, or completed
|
mcpEnabled |
spring.opencrawling.connector.aps.mcp.enabled |
false |
Enable dynamic workflow discovery via APS MCP Server |
mcpUrl |
spring.opencrawling.connector.aps.mcp.url |
"" |
Optional endpoint URL for the APS MCP Server |
| Format | Behaviour |
|---|---|
(empty) or /
|
Scans all process instances matching configured criteria |
invoiceApproval |
Scans process instances matching process definition key invoiceApproval
|
| Metadata key | Description |
|---|---|
processDefinitionId |
Process definition unique ID (e.g. invoiceApproval:2:89201) |
processDefinitionKey |
Process definition key (e.g. invoiceApproval) |
processDefinitionName |
Human-readable workflow name (e.g. Invoice Approval Workflow) |
businessKey |
Workflow business tracking key (e.g. INV-2026-9041) |
startUserId |
User ID that initiated the process |
startTime / endTime
|
Workflow execution timestamps |
durationInMillis |
Execution duration in milliseconds |
tenantId |
Multi-tenant identifier (if applicable) |
aps_proc_inst_id |
Native Process Instance ID for collocated DB joins |
aps_scope_id |
Engine scope identifier for entity-level authorization |
aps_scope_type |
Scope type identifier (processInstance) |
aps_identity_users |
List of allowed user identities |
aps_identity_groups |
List of allowed group identities |
aps_var_<varName> |
Dynamically mapped BPMN process variable |
aps_task_<taskName>_assignee |
User task assignee |
oc-crawler:
environment:
CONNECTOR_TYPE: aps
SCAN_PATH: /
APS_URL: http://aps:8080/activiti-app/api/enterprise
APS_USERNAME: [email protected]
APS_PASSWORD: admin
APS_INCLUDE_VARIABLES: "true"
APS_INCLUDE_TASKS: "true"
APS_INCLUDE_ATTACHMENTS: "true"Module: oc-cmis-repository-connector
Class: CmisRepositoryConnector
Spring Bean: @Component (activated when CONNECTOR_TYPE=cmis or spring.opencrawling.connector.type=cmis)
Dedicated Guide: OASIS CMIS Repository Connector
Connects to any OASIS CMIS 1.0 / 1.1 compliant Enterprise Content Management (ECM) repository — including Alfresco Content Services, OpenText Documentum, IBM FileNet P8, Apache Chemistry InMemory / FileShare, and Nuxeo — using the high-performance CMIS 1.1 Browser Binding (JSON over HTTP/REST).
Implemented natively with Java 25 HttpClient (zero legacy Apache Chemistry dependencies), the connector parallelizes folder hierarchy scanning, metadata enrichment, and binary content extraction using Java 25 Virtual Threads (StructuredTaskScope).
It supports:
-
Multiple Crawl Modes: Recursive folder traversal (
folder), CMIS-SQL relational queries (query), and incremental change log synchronization. -
Versioning Policies:
latest_major(official releases),latest(including minor revisions), orall(complete history). -
Aspects & Secondary Types: Full extraction of
cmis:secondaryObjectTypeIdsand arbitrary custom metadata namespaces. -
Zero-Trust Security: Maps CMIS Access Control Lists (ACLs) and ACEs into OIS
SecurityConfigpermission rules. - Claim Check Stream Pattern: Routes binary streams directly to local disk, Apache Ozone, or AWS S3, passing lightweight URI references to Kafka.
| Property key | Spring Property Key | Default | Description |
|---|---|---|---|
endpointUrl |
spring.opencrawling.connector.cmis.endpoint-url |
http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/browser |
CMIS Browser Binding service endpoint |
repositoryId |
spring.opencrawling.connector.cmis.repository-id |
"" |
Target repository ID (auto-discovered if empty) |
username |
spring.opencrawling.connector.cmis.username |
admin |
Basic auth username |
password |
spring.opencrawling.connector.cmis.password |
admin |
Basic auth password |
bindingType |
spring.opencrawling.connector.cmis.binding-type |
browser |
Protocol binding (browser or atompub) |
crawlMode |
spring.opencrawling.connector.cmis.crawl-mode |
folder |
Ingestion mode (folder or query) |
rootFolderPath |
spring.opencrawling.connector.cmis.root-folder-path |
/ |
Root folder path for folder mode |
rootFolderId |
spring.opencrawling.connector.cmis.root-folder-id |
"" |
Optional starting folder object ID |
includeSubfolders |
spring.opencrawling.connector.cmis.include-subfolders |
true |
Recursively traverse folder hierarchy |
excludedFolderPaths |
spring.opencrawling.connector.cmis.excluded-folder-paths |
/Sites/trash,/System |
Comma-separated paths to ignore |
cmisQuery |
spring.opencrawling.connector.cmis.cmis-query |
SELECT * FROM cmis:document |
CMIS-SQL query for query mode |
versionsMode |
spring.opencrawling.connector.cmis.versions-mode |
latest_major |
Version filter (latest_major, latest, all) |
includeContentStream |
spring.opencrawling.connector.cmis.include-content-stream |
true |
Fetch binary content stream for text parsing |
maxContentSizeBytes |
spring.opencrawling.connector.cmis.max-content-size-bytes |
52428800 |
Max content stream size in bytes (50 MB) |
includeAcls |
spring.opencrawling.connector.cmis.include-acls |
true |
Map ACEs to OIS security permissions |
includeSecondaryTypes |
spring.opencrawling.connector.cmis.include-secondary-types |
true |
Extract secondary object types and aspects |
batchSize |
spring.opencrawling.connector.cmis.batch-size |
100 |
Objects per page request |
timeoutSeconds |
spring.opencrawling.connector.cmis.timeout-seconds |
30 |
HTTP request timeout in seconds |
| Format | Behaviour |
|---|---|
(empty) or /
|
Starts recursive scan from root folder (/) |
/Company Home/Sites/my-site |
Recursively scans specified repository folder path |
SELECT * FROM cmis:document WHERE ... |
Executes CMIS-SQL query directly in query mode |
d9f6a1e0-... (UUID) |
Targets folder with matching CMIS object ID |
| Metadata key | Description |
|---|---|
name |
Document title / filename |
cmis.objectId |
Unique CMIS object identifier |
cmis.name |
CMIS document name |
cmis.baseTypeId |
Base type (e.g. cmis:document) |
cmis.objectTypeId |
Specific type definition (e.g. cm:content) |
cmis.secondaryObjectTypeIds |
Applied aspects / secondary types list |
cmis.createdBy / cmis.lastModifiedBy
|
Creator and modifier usernames |
cmis.creationDate / cmis.lastModificationDate
|
ISO-8601 timestamps |
cmis.versionLabel |
Document version string (e.g. 1.0) |
cmis.isLatestVersion / cmis.isLatestMajorVersion
|
Version status flags |
cmis.contentStreamLength / cmis.contentStreamMimeType
|
Binary size and MIME type |
cmis.path |
Full repository path |
<customProperty> |
Any custom aspect or schema properties |
oc-crawler:
image: opencrawling/oc-runtime:latest
environment:
CONNECTOR_TYPE: cmis
SCAN_PATH: /Company Home
CMIS_ENDPOINT_URL: http://alfresco:8080/alfresco/api/-default-/public/cmis/versions/1.1/browser
CMIS_REPOSITORY_ID: -default-
CMIS_USERNAME: admin
CMIS_PASSWORD: admin
CMIS_CRAWL_MODE: folder
CMIS_INCLUDE_SUBFOLDERS: "true"
CMIS_VERSIONS_MODE: latest_major
CMIS_INCLUDE_ACLS: "true"
CMIS_INCLUDE_CONTENT_STREAM: "true"Module: oc-jdbc-repository-connector
Class: JdbcRepositoryConnector
Security Mapper: JdbcSecurityMapper
Crawl Mode Enum: JdbcCrawlMode
Spring Bean: @Component (activated when CONNECTOR_TYPE=jdbc or spring.opencrawling.connector.type=jdbc)
Dedicated Guide: Relational Database (JDBC) Connector
Connects natively to any JDBC-compliant Relational Database Management System (RDBMS) — including PostgreSQL, MySQL, MariaDB, Oracle Database, Microsoft SQL Server, IBM DB2, SQLite, DuckDB, H2, and Snowflake — via standard JDBC 4.2+ drivers.
The connector supports dual-path ingestion:
-
Tabular RAG & Auto-Narrativization: Ingests relational rows from tables, views, or arbitrary SQL queries, introspects schema metadata via
getSchema(basePath)to empower Spring AITemplateGenerationCopilot, and renders rows into cohesive natural-language narrative text (or deterministic Markdown key-values) for embedding. -
Binary BLOB / CLOB Streaming via Claim Check: Directly streams database binary columns (
BLOB,BYTEA,RAW,CLOB) into the activeClaimCheckStore(Local disk, Apache Ozone, AWS S3) with automated magic byte sniffing (PDF, PNG, JPEG, ZIP, GIF, WEBP) and Apache Tika text/OCR extraction without JVM heap exhaustion.
Built on Java 25 Virtual Threads (StructuredTaskScope) and HikariCP connection pooling, it features multi-table concurrent scanning, engine-specific streaming cursors (PostgreSQL autocommit disabled, MySQL streaming fetch), stateful High-Water Mark (HWM) incremental delta crawling, soft-delete tombstone emission (DocumentAction.DELETE), and zero-trust column-to-ACL security mapping (JdbcSecurityMapper).
| Property key | Spring Property Key | Default | Description |
|---|---|---|---|
url |
spring.opencrawling.connector.jdbc.url |
jdbc:h2:mem:opencrawling;DB_CLOSE_DELAY=-1 |
JDBC connection URL |
driverClassName |
spring.opencrawling.connector.jdbc.driver-class-name |
"" |
Fully qualified driver class name (auto-detected if blank) |
username |
spring.opencrawling.connector.jdbc.username |
sa |
Database authentication username |
password |
spring.opencrawling.connector.jdbc.password |
"" |
Database authentication password |
crawlMode |
spring.opencrawling.connector.jdbc.mode |
table |
Ingestion mode (table or query) |
tableName |
spring.opencrawling.connector.jdbc.table-name |
"" |
Target table or view name |
schemaName |
spring.opencrawling.connector.jdbc.schema-name |
"" |
Target database schema qualifier |
primaryKeyColumns |
spring.opencrawling.connector.jdbc.primary-key-columns |
id |
Primary key column name(s), comma-separated |
titleColumn |
spring.opencrawling.connector.jdbc.title-column |
title |
Column mapped as document title |
excludedColumns |
spring.opencrawling.connector.jdbc.excluded-columns |
"" |
Columns to omit from indexing (e.g. sensitive data) |
querySql |
spring.opencrawling.connector.jdbc.query-sql |
"" |
Custom SQL query executed when crawlMode=query
|
blobColumnName |
spring.opencrawling.connector.jdbc.blob-column-name |
"" |
Binary BLOB column (auto-detected if blank) |
fileNameColumn |
spring.opencrawling.connector.jdbc.file-name-column |
"" |
Attachment filename column |
mimeTypeColumn |
spring.opencrawling.connector.jdbc.mime-type-column |
"" |
Attachment MIME type column |
incrementalEnabled |
spring.opencrawling.connector.jdbc.incremental-enabled |
false |
Enable High-Water Mark incremental crawl |
hwmColumn |
spring.opencrawling.connector.jdbc.hwm-column |
updated_at |
High-Water Mark column name |
hwmType |
spring.opencrawling.connector.jdbc.hwm-type |
timestamp |
HWM type: timestamp or numeric
|
softDeleteEnabled |
spring.opencrawling.connector.jdbc.soft-delete-enabled |
false |
Enable soft-delete tombstone emission |
softDeleteColumn |
spring.opencrawling.connector.jdbc.soft-delete-column |
is_deleted |
Soft-delete status column |
softDeleteValue |
spring.opencrawling.connector.jdbc.soft-delete-value |
true |
Soft-delete matching value |
securityEnabled |
spring.opencrawling.connector.jdbc.security-enabled |
false |
Extract column-based zero-trust ACLs |
userColumns |
spring.opencrawling.connector.jdbc.user-columns |
"" |
Comma-separated user identity columns |
groupColumns |
spring.opencrawling.connector.jdbc.group-columns |
"" |
Comma-separated group/role columns |
tenantColumn |
spring.opencrawling.connector.jdbc.tenant-column |
"" |
Column containing tenant identifier |
defaultPermission |
spring.opencrawling.connector.jdbc.default-permission |
read |
Default permission for mapped identities |
fetchSize |
spring.opencrawling.connector.jdbc.fetch-size |
1000 |
Server-side JDBC cursor fetch size |
batchSize |
spring.opencrawling.connector.jdbc.batch-size |
100 |
Structured concurrency batch size |
multiTableParallelEnabled |
spring.opencrawling.connector.jdbc.multi-table-parallel-enabled |
true |
Enable parallel multi-table scanning |
narrativizationTemplate |
spring.opencrawling.connector.jdbc.narrativization-template |
"" |
Optional Mustache template for tabular rows |
| Format | Behaviour |
|---|---|
support_tickets |
Crawls table support_tickets in table mode |
crm.customers |
Crawls table customers within schema crm
|
customers,orders,invoices |
Concurrently scans all three tables in parallel via StructuredTaskScope
|
SELECT * FROM tickets WHERE ... |
Executes custom SQL query directly in query mode |
| (empty) | Uses configured tableName or querySql
|
| Metadata key | Description |
|---|---|
table_name |
Source database table or query identifier |
primary_key |
Primary key value |
title / name
|
Record display title |
is_tabular |
Flag set to true for structured relational rows |
is_blob |
Flag set to true for binary attachments |
is_image |
Flag set to true when binary matches image magic bytes |
media_type |
Record type (tabular, image, etc.) |
mimeType |
Sniffed or mapped MIME type |
tenant_id |
Mapped tenant identifier |
<columnName> |
Strongly typed column values |
oc-crawler:
image: opencrawling/oc-runtime:latest
environment:
CONNECTOR_TYPE: jdbc
SCAN_PATH: support_tickets
JDBC_URL: jdbc:postgresql://postgres-source:5432/crm_prod
JDBC_DRIVER_CLASS_NAME: org.postgresql.Driver
JDBC_USERNAME: crm_reader
JDBC_PASSWORD: crm_password
JDBC_TABLE_NAME: support_tickets
JDBC_PRIMARY_KEY_COLUMNS: id
JDBC_TITLE_COLUMN: title
JDBC_SECURITY_ENABLED: "true"
JDBC_USER_COLUMNS: owner_id
JDBC_GROUP_COLUMNS: department_id
JDBC_SOFT_DELETE_ENABLED: "true"
JDBC_SOFT_DELETE_COLUMN: is_deleted
JDBC_SOFT_DELETE_VALUE: "true"Output connectors receive a RepositoryDocument and persist it directly (bypassing Kafka — used in the direct/standalone execution mode).
Module: oc-vector-output-connector
Class: VectorOutputConnector
Spring Bean: @Component
Parses document content using Apache Tika (with full parser support for PDF, Word, PowerPoint, Excel, HTML, plain text, and more), splits the extracted text into overlapping chunks, generates embeddings by calling the configured embedding model, and writes the resulting vectors to PGVector (PostgreSQL with the pgvector extension).
This connector is used in the direct output mode (where the crawler and vectorisation happen in the same JVM process). In the decoupled mode, the equivalent pipeline is executed across three separate microservices: oc-ingestion-consumer, oc-embedding-service, and oc-runtime (VectorStoreWriterConsumer).
| Property | Default | Description |
|---|---|---|
spring.ai.vectorstore.pgvector.url |
— | JDBC URL of the PGVector database |
spring.ai.vectorstore.pgvector.username |
— | Database username |
spring.ai.vectorstore.pgvector.password |
— | Database password |
spring.ai.vectorstore.pgvector.initialize-schema |
true |
Auto-creates the vector_store tables on startup |
spring.ai.vectorstore.pgvector.dimensions |
1536 |
Default vector dimensions (must match the embedding model) |
The connector maintains four separate tables to support different embedding model dimension sizes simultaneously:
| Table | Dimensions | Typical model |
|---|---|---|
vector_store |
1536 (default) | OpenAI text-embedding-3-small
|
vector_store_384 |
384 |
all-minilm (Ollama) |
vector_store_768 |
768 |
nomic-embed-text (Ollama) |
vector_store_1024 |
1024 |
mxbai-embed-large (Ollama) |
The correct table is selected automatically based on the length of the embedding vector returned by the model.
Apache Tika's AutoDetectParser handles format detection and extraction. If parsing fails for a specific file (e.g., a FreeMarker .ftl template mistakenly detected as RSS/XML), the connector logs a warning and falls back to reading the file as UTF-8 plain text.
Module: oc-milvus-output-connector
Class: MilvusOutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=milvus)
Persists precomputed vector embeddings and text chunks directly into a Milvus vector database collection. It supports standard index types (e.g., HNSW), custom metric types (e.g., COSINE), and user token authentication.
In the decoupled architecture, MilvusStoreWriterConsumer consumes embedded chunks from the Kafka opencrawling-embedded topic and saves them using this connector.
| Property | Default | Description |
|---|---|---|
SPRING_OPENCRAWLING_OUTPUT_MILVUS_URI |
http://localhost:19530 |
URI/Host endpoint of the Milvus standalone instance |
SPRING_OPENCRAWLING_OUTPUT_MILVUS_TOKEN |
root:Milvus |
Authentication token or username:password |
SPRING_OPENCRAWLING_OUTPUT_MILVUS_COLLECTION_NAME |
enterprise_kb |
Target Milvus collection name |
SPRING_OPENCRAWLING_OUTPUT_MILVUS_VECTOR_FIELD_NAME |
embeddings |
Name of the field containing the vector embeddings |
SPRING_OPENCRAWLING_OUTPUT_MILVUS_DIMENSIONS |
1024 |
Vector dimension size (e.g., 1024 for mxbai-embed-large) |
Module: oc-opensearch2-output-connector
Class: OpenSearch2OutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=opensearch2)
Persists precomputed vector embeddings and text chunks directly into an OpenSearch 2.x instance or cluster. On startup, the connector checks for the existence of the target index and automatically initializes it with k-NN HNSW settings and cosine similarity. It relocates internal org.opensearch classes under a shaded packaging boundary (org.opencrawling.shaded.opensearch2) to avoid classpath namespace conflicts with OpenSearch 3.x.
It also contains built-in connection retries (up to 10 attempts, sleeping 3 seconds between attempts) to gracefully handle container orchestration startup delays.
| Property | Default | Description |
|---|---|---|
spring.opencrawling.output.opensearch2.uris |
http://localhost:9200 |
URIs of the OpenSearch 2.x nodes (comma-separated) |
spring.opencrawling.output.opensearch2.username |
admin |
Username for basic authentication |
spring.opencrawling.output.opensearch2.password |
admin |
Password for basic authentication |
spring.opencrawling.output.opensearch2.index-name |
enterprise_kb |
Target index name |
spring.opencrawling.output.opensearch2.dimensions |
1024 |
Vector dimension size (e.g., 1024 for mxbai-embed-large) |
Module: oc-opensearch3-output-connector
Class: OpenSearch3OutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=opensearch3)
Persists precomputed vector embeddings and text chunks directly into an OpenSearch 3.x instance. Similar to the 2.x connector, it automatically checks and boots up the target index using k-NN settings on startup. It includes built-in connection retries (up to 10 attempts, sleeping 3 seconds between attempts) to gracefully wait for OpenSearch containers to become healthy during multi-container orchestration.
| Property | Default | Description |
|---|---|---|
spring.opencrawling.output.opensearch3.uris |
http://localhost:9200 |
URIs of the OpenSearch 3.x nodes (comma-separated) |
spring.opencrawling.output.opensearch3.username |
admin |
Username for basic authentication |
spring.opencrawling.output.opensearch3.password |
admin |
Password for basic authentication |
spring.opencrawling.output.opensearch3.index-name |
enterprise_kb |
Target index name |
spring.opencrawling.output.opensearch3.dimensions |
1024 |
Vector dimension size (e.g., 1024 for mxbai-embed-large) |
Module: oc-qdrant-output-connector
Class: QdrantOutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=qdrant)
Persists precomputed vector embeddings and text chunks directly into a Qdrant vector database collection (self-hosted or Qdrant Cloud). It utilizes Qdrant's high-performance gRPC Java Client (io.qdrant:client) for low-latency batch upserts of PointStruct objects.
Upon initialization via QdrantCollectionInitializer, it automatically verifies or provisions the target Qdrant collection with configured vector parameters (dimensions, Cosine/Dot/Euclid distance metrics) and creates KEYWORD payload indexes for security ACL fields (security_allowed_read, security_denied_read). This allows sub-millisecond ACL pre-filtering during similarity search in McpVectorServer.
In the decoupled architecture, QdrantStoreWriterConsumer consumes embedded chunks from the Kafka opencrawling-embedded topic and persists them into Qdrant.
| Property | Default | Description |
|---|---|---|
spring.opencrawling.output.qdrant.host |
localhost |
Hostname of the Qdrant instance |
spring.opencrawling.output.qdrant.port |
6334 |
gRPC port (6334 by default, REST on 6333) |
spring.opencrawling.output.qdrant.api-key |
"" |
Optional API key for Qdrant Cloud or Enterprise authentication |
spring.opencrawling.output.qdrant.collection-name |
enterprise_kb |
Target Qdrant collection name |
spring.opencrawling.output.qdrant.dimensions |
1024 |
Vector dimension size (e.g. 1024 for mxbai-embed-large) |
spring.opencrawling.output.qdrant.distance |
COSINE |
Vector distance metric (COSINE, DOT, EUCLID) |
spring.opencrawling.output.qdrant.quantization |
NONE |
Quantization type (NONE, SCALAR, BINARY) |
spring.opencrawling.output.qdrant.use-tls |
false |
Enable TLS for secure gRPC connection |
spring.opencrawling.output.qdrant.batch-size |
500 |
Point batch size for vector upsert operations |
Module: oc-vespa-output-connector
Class: VespaOutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=vespa)
Persists precomputed vector embeddings and text chunks directly into Vespa, Yahoo's open-source big data serving engine combining ANN vector search with BM25 lexical ranking.
Document chunks and embeddings are fed using the official com.yahoo.vespa:vespa-feed-client HTTP/2 client into Vespa document types with full support for Open Ingestion Standard (OIS) ACL pre-filtering, dynamic multi-dimension vector routing, mTLS security, and Admin UI Model Insights.
-
Document/v1 feeding via official HTTP/2 client: Both
VespaOutputConnector.send()(direct SPI path) andVespaStoreWriterConsumer(decoupled Kafka writer foropencrawling-embedded) stream document chunks usingvespa-feed-client, which manages HTTP/2 multiplexed connection pools, dynamic throttling, and automatic retries for transient429/503responses. -
Dynamic Multi-Dimension Routing:
VespaDocumentMapper.resolveDocumentType()inspects each chunk's actual vector dimension and dynamically routes it to a dimension-specific Vespa document type:-
384dimensions$\rightarrow$ opencrawling_chunk_384(e.g.all-minilm) -
768dimensions$\rightarrow$ opencrawling_chunk_768(e.g.nomic-embed-text) -
1024dimensions$\rightarrow$ opencrawling_chunk_1024(e.g.mxbai-embed-large) - Any other dimension
$\rightarrow$ Fallback to the configured default document type (opencrawling_chunk). This allows mixing embedding models across jobs without changing configuration or redeploying schemas.
-
-
ACL-Aware Security Indexing: Each document carries
security_allowed_read,security_denied_read, andsecurity_inheritancefields derived from the OIS security model, enabling exact permission filtering. -
Structured Schema Safety: Dynamic metadata fields are consolidated into a single
metadata_jsonblob to conform strictly to Vespa's strongly typed schema requirements. -
Admin UI Model Insights & Deployment: Backed by
/api/vespa/*REST endpoints (VespaInsightsService/VespaInsightsController), providing live engine health (/api/vespa/health), per-document-type chunk counts (/api/vespa/document-counts), hybrid/BM25 query testing (/api/vespa/query), and one-click bundled schema deployment (/api/vespa/deploy/bundled). -
Vespa-Native Secure MCP Server:
VespaMcpVectorServerexposesvespaSecureVectorSearch(hybrid BM25 + vector similarity ranking),vespaGetDocumentContent, andvespaListAccessibleSourcesover SSE/HTTP, pushing ACLsecurity_denied_readchecks into Vespa YQL queries while maintaining Java-level OIS re-checking.
All properties are bound under spring.opencrawling.output.vespa.*:
| Property | Default | Description |
|---|---|---|
spring.opencrawling.output.vespa.endpoint |
http://localhost:8080 |
Vespa container Document/Search API endpoint |
spring.opencrawling.output.vespa.namespace |
opencrawling |
Vespa Document ID namespace |
spring.opencrawling.output.vespa.document-type |
opencrawling_chunk |
Default document type used when embedding length is not 384, 768, or 1024 |
spring.opencrawling.output.vespa.dimensions |
1024 |
Fallback vector dimension matching default document type's tensor schema |
spring.opencrawling.output.vespa.timeout-seconds |
30 |
Startup connectivity check timeout in seconds |
spring.opencrawling.output.vespa.tls-enabled |
false |
Enable mTLS client certificate authentication (Vespa Cloud) |
spring.opencrawling.output.vespa.tls-certificate |
(none) | Path to client certificate PEM file |
spring.opencrawling.output.vespa.tls-private-key |
(none) | Path to client private key PEM file |
spring.opencrawling.output.vespa.tls-ca-certificates |
(none) | Path to CA certificates PEM file |
{
"fields": {
"chunk_id": "doc-123_a1b2c3",
"text": "Enterprise search chunk content...",
"uri": "file:///data/report.pdf",
"acl": "finance",
"lastModified": "2026-08-01T10:00:00Z",
"security_inheritance": true,
"security_allowed_read": ["user1", "finance-group"],
"security_denied_read": ["external-contractor"],
"metadata_json": "{\"title\":[\"Q3 Financial Report\"],\"mimeType\":[\"application/pdf\"]}",
"embedding": { "values": [0.0123, -0.0456, 0.0891] }
}
}# Spin up Vespa with bundled schema auto-deploy via Docker Compose
docker compose -f oc-vespa-output-connector/docker/docker-compose.yml up -d
# Standalone connector smoke test (feeds chunks & asserts dynamic routing + ACLs)
./scripts/test-vespa-connector.sh
# Decoupled Kafka pipeline test with Vespa
./scripts/test-vespa-decoupled.shModule: oc-solr-output-connector
Class: SolrOutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=solr)
Persists precomputed vector embeddings and document text chunks into Apache Solr (v10.x / v9.x) using SolrJ 10 native JDK HTTP Client (HttpJdkSolrClient for standalone, CloudSolrClient for SolrCloud mode).
Document chunks are indexed using Solr's solr.DenseVectorField with customizable HNSW graph parameters (hnswMaxConnections, hnswBeamWidth, similarityFunction). It features dynamic REST schema auto-provisioning (SolrCollectionInitializer), Solr 10 vector quantization (scalar, binary), efSearch query tuning, OIS zero-trust ACL security fields, and decoupled Kafka writer consumer execution (SolrStoreWriterConsumer).
For full configuration reference, schema details, and queries, see the Apache Solr Output Connector Wiki Page.
All properties are bound under spring.opencrawling.output.solr.*:
| Property | Default | Description |
|---|---|---|
spring.opencrawling.output.solr.mode |
standalone |
Solr deployment mode: standalone or cloud
|
spring.opencrawling.output.solr.url |
http://localhost:8983/solr |
Base HTTP URL of standalone Solr instance |
spring.opencrawling.output.solr.zk-host |
localhost:2181 |
ZooKeeper connection string for SolrCloud mode |
spring.opencrawling.output.solr.collection |
enterprise_kb |
Target Solr collection / core name |
spring.opencrawling.output.solr.dimensions |
1024 |
Vector embedding dimension size |
spring.opencrawling.output.solr.similarity |
cosine |
Similarity metric: cosine, dot_product, or euclidean
|
spring.opencrawling.output.solr.vector-encoding |
FLOAT32 |
Solr 10 vector encoding: FLOAT32 or BYTE
|
spring.opencrawling.output.solr.quantization |
none |
Solr 10 quantization: none, scalar, or binary
|
spring.opencrawling.output.solr.hnsw-max-connections |
16 |
HNSW graph max connections ( |
spring.opencrawling.output.solr.hnsw-beam-width |
100 |
HNSW graph beam width ( |
spring.opencrawling.output.solr.ef-search |
100 |
Solr 10 efSearch query precision parameter |
spring.opencrawling.output.solr.commit-within-ms |
1000 |
Soft-commit latency limit in milliseconds |
# Spin up standalone Solr 10.x container via Docker Compose
docker compose -f oc-solr-output-connector/docker/docker-compose.yml up -d
# Decoupled Kafka pipeline test with Solr 10
./scripts/test-solr-decoupled.shModule: oc-luxir-output-connector
Class: LuxirOutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=luxir)
Persists precomputed vector embeddings, document text chunks, and metadata into Luxir using its native HTTP JSON API.
Document chunks are indexed using Luxir's dynamic schema type conventions (_t, _s, _ss, _v, _vs) and dense vector fields with customizable metrics (cosine, l2, ip). Zero-Trust ACL inheritance is mapped to string (security_inheritance_s: "true"/"false") for seamless dynamic schema indexing. Features include automatic collection creation and vector schema provisioning (LuxirCollectionInitializer), OIS v1.1 tombstone deletion handling (delete_ids), zero-trust ACL security tokens, Admin UI integration, and decoupled Kafka writer consumer execution (LuxirStoreWriterConsumer).
For full configuration reference, schema details, and queries, see the Luxir Output Connector Wiki Page.
All properties are bound under spring.opencrawling.output.luxir.*:
| Property | Default | Description |
|---|---|---|
spring.opencrawling.output.luxir.endpoint |
http://localhost:9400 |
HTTP endpoint URL of the Luxir instance |
spring.opencrawling.output.luxir.collection |
opencrawling |
Target Luxir collection name |
spring.opencrawling.output.luxir.vector-field |
embedding_v |
Vector field name in Luxir (_v suffix convention) |
spring.opencrawling.output.luxir.dimensions |
1024 |
Vector dimensionality (matches default mxbai-embed-large model) |
spring.opencrawling.output.luxir.similarity |
cosine |
Distance metric: cosine, l2, or ip
|
spring.opencrawling.output.luxir.auto-commit |
true |
Whether to automatically commit index updates |
spring.opencrawling.output.luxir.commit-within-ms |
1000 |
Soft-commit window in milliseconds |
spring.opencrawling.output.luxir.timeout-seconds |
30 |
HTTP connection and socket timeout in seconds |
# Spin up standalone Luxir container via Docker Compose
docker compose -f oc-luxir-output-connector/docker/docker-compose.yml up -d
# Decoupled Kafka pipeline test with Luxir
./scripts/test-luxir-decoupled.shModule: oc-seatunnel-output-connector
Class: SeaTunnelOutputConnector
Spring Bean: @Component (activated when spring.opencrawling.output.type=seatunnel)
Integrates Apache SeaTunnel (v2.3.13) into OpenCrawling as a distributed data integration engine and fan-out orchestrator. It enables high-throughput document crawling, text extraction, token chunking, zero-trust ACL security mapping, and dense vector embeddings to fan out directly into Apache SeaTunnel pipelines powered by the Zeta Engine, Apache Flink, or Apache Spark.
Through SeaTunnel, OpenCrawling streams can be routed to over 100+ destination sinks simultaneously (ClickHouse, Milvus, Apache Iceberg, StarRocks, Qdrant, Elasticsearch, etc.). Features automated HOCON DAG synthesis (SeaTunnelJobConfigBuilder), Zeta Engine REST API v2 orchestration (SeaTunnelRestClient), OIS v1.1 tombstone deletion handling (-D / RowKind.DELETE), stock SeaTunnel cluster compatibility without requiring custom JARs, Admin UI dynamic health checking, and decoupled Kafka writer consumer execution (SeaTunnelStoreWriterConsumer).
For full configuration reference, schema details, and queries, see the Apache SeaTunnel Output Connector Wiki Page.
All properties are bound under spring.opencrawling.output.seatunnel.*:
| Property | Default | Description |
|---|---|---|
spring.opencrawling.output.seatunnel.rest-url |
http://localhost:8080 |
HTTP endpoint URL of the SeaTunnel Zeta master REST API (typically mapped to port 8088 or 8080) |
spring.opencrawling.output.seatunnel.job-name |
opencrawling_ingestion_pipeline |
SeaTunnel job name identifier |
spring.opencrawling.output.seatunnel.job-mode |
STREAMING |
Execution mode: STREAMING or BATCH
|
spring.opencrawling.output.seatunnel.checkpoint-interval-ms |
5000 |
State checkpoint interval in milliseconds |
spring.opencrawling.output.seatunnel.parallelism |
4 |
Execution parallelism degree across Zeta workers |
spring.opencrawling.output.seatunnel.kafka-bootstrap-servers |
localhost:9092 |
Kafka broker bootstrap servers for the intermediate fan-out topic |
spring.opencrawling.output.seatunnel.kafka-topic |
opencrawling-embedded |
Topic containing embedded document chunks |
spring.opencrawling.output.seatunnel.kafka-group-id |
seatunnel-ingestion-consumer |
Consumer group ID for the SeaTunnel Kafka source |
spring.opencrawling.output.seatunnel.target-sinks |
console |
Comma-separated list of target SeaTunnel sinks (e.g. console, clickhouse, milvus, qdrant, iceberg) |
spring.opencrawling.output.seatunnel.dimensions |
1024 |
Vector dimensionality (matches default mxbai-embed-large) |
spring.opencrawling.output.seatunnel.auto-submit-job |
true |
Automatically submit the generated HOCON DAG to SeaTunnel on connector startup |
spring.opencrawling.output.seatunnel.timeout-seconds |
30 |
HTTP connection and socket timeout in seconds |
# Spin up standalone Apache SeaTunnel Zeta cluster via Docker Compose
docker compose -f oc-seatunnel-output-connector/docker/docker-compose.yml up -d
# Decoupled Kafka pipeline test with Apache SeaTunnel
./scripts/test-seatunnel-decoupled.shModule: oc-ozone-output-connector
Class: org.opencrawling.ozone.OzoneOutputConnector (decoupled writer: OzoneMigrationWriterConsumer)
Spring Bean: @Component (activated when spring.opencrawling.output.type=ozone)
Migrates enterprise content bit for bit into Apache Ozone volumes and buckets. It runs only in Migration Mode (opencrawling.pipeline.mode=migration, or pipelineMode: migration per job): Tika extraction, chunking and embeddings are skipped. A job that uses this output in RAG mode is rejected with HTTP 409.
Each UPSERT writes the original binary (SHA-256 computed while streaming), a <key>.ois.json sidecar with metadata, Zero-Trust ACLs and contentRef, and an internal index entry. DELETE removes them (DELETE_KEY) or also writes .tombstones/<key>.ois.json (ARCHIVE_TOMBSTONE). There are two transports: NATIVE (Ozone RPC, the default and about 30% faster) and S3G (S3 Gateway, with parallel multipart uploads for large objects).
For architecture, object layout, tuning and measurements, see the Apache Ozone Output Connector Wiki Page.
All properties are bound under spring.opencrawling.output.ozone.*:
| Property | Default | Description |
|---|---|---|
client-type |
NATIVE |
NATIVE (ofs/RPC) or S3G (S3 Gateway HTTP) |
volume / bucket
|
opencrawling / migration
|
Target volume and bucket (the Admin UI form suggests s3v / migration) |
om-host / om-port
|
localhost / 9862
|
Ozone Manager RPC endpoint (NATIVE) |
s3-endpoint |
http://localhost:9878 |
S3 Gateway endpoint (S3G) |
access-key / secret-key
|
any / any
|
S3 Gateway credentials |
auto-create-bucket |
true |
Create the volume/bucket if missing |
key-strategy |
HIERARCHICAL |
HIERARCHICAL (from the relative path) or FLAT (sanitized document id) |
sidecar-suffix |
.ois.json |
Suffix of the OIS metadata sidecar |
tombstone-action |
DELETE_KEY |
DELETE_KEY or ARCHIVE_TOMBSTONE
|
allow-in-memory-fallback |
false |
For testing only. When false, an unreachable OM fails the connector. |
consumer-group |
opencrawling-ozone-migration-group |
Dedicated Kafka consumer group of the decoupled writer |
consumer-concurrency |
3 |
Writer threads (effective parallelism = min(threads, topic partitions)) |
multipart-threshold / multipart-part-size / multipart-concurrency
|
256MB / 16MB / 4
|
S3G multipart uploads (0 threshold = disabled) |
Related: spring.opencrawling.kafka.topic.partitions (3) and spring.opencrawling.crawler.concurrency (4). See the Configuration Guide.
# Migration mode unit + live checks
./scripts/test-ozone-migration.sh
# Decoupled migration: source Ozone (claim check) -> Kafka -> writer -> target Ozone
./scripts/test-ozone-migration-decoupled.sh
# Same, over the S3 transports
OUTPUT_OZONE_CLIENT_TYPE=S3G CLAIM_CHECK_OZONE_CLIENT_TYPE=S3 ./scripts/test-ozone-migration-decoupled.shTransformation connectors are not Java classes but named configurations stored in connectors.json and managed via the Admin UI. They define which embedding engine and model the oc-embedding-service should use when processing chunks from Kafka.
Runs a local embedding model via the Ollama server. No API key required.
| Config key | Example value | Description |
|---|---|---|
engine |
ollama |
Engine type identifier |
model |
mxbai-embed-large |
Ollama model name (must be pre-pulled) |
baseUrl |
http://localhost:11434 |
Ollama server base URL |
Recommended models by dimension:
| Model | Dimensions | Pull command |
|---|---|---|
mxbai-embed-large |
1024 | ollama pull mxbai-embed-large |
nomic-embed-text |
768 | ollama pull nomic-embed-text |
all-minilm |
384 | ollama pull all-minilm |
Uses the OpenAI Embeddings API. Requires an API key.
| Config key | Example value | Description |
|---|---|---|
engine |
openai |
Engine type identifier |
model |
text-embedding-3-small |
OpenAI model name |
apiKey |
sk-... |
OpenAI API key |
To implement a custom Repository Connector:
- Create a new Maven module (e.g.
oc-s3-repository-connector). - Add
oc-coreas a dependency. - Implement
RepositoryConnector:
@Component
public class S3RepositoryConnector implements RepositoryConnector {
@Override
public String getName() { return "S3Connector"; }
@Override
public void connect() throws Exception { /* initialise S3 client */ }
@Override
public void disconnect() throws Exception { /* shutdown */ }
@Override
public Flux<RepositoryDocument> scan(String basePath) {
return Flux.create(sink -> {
// list S3 objects under basePath prefix
// for each object: sink.next(new RepositoryDocument(...))
sink.complete();
});
}
}- Add the module to the root
pom.xmland tooc-runtime's dependencies. - Register it in
docker-compose-decoupled.ymlwithCONNECTOR_TYPE: s3.
See Repository Connector Execution Modes for how connectors are wired into the runtime.