Connector Document Sync#
RAGFlow connectors ingest content from external sources (blob storage, SharePoint, Notion, GitHub, relational databases) and must reliably translate each external object into a stable RAGFlow document ID, then avoid re-downloading and re-processing objects that haven't changed. Two mechanisms handle this: deterministic ID construction and fingerprint-based change detection.
Document ID Construction#
Every connector builds a document ID from native source identifiers, not from content. The pattern is consistent across connectors:
| Connector | ID format | Source |
|---|---|---|
| Blob (S3/R2/GCS/OCI) | {bucket_type}:{bucket_name}:{object_key} | |
| SharePoint | {drive_id}:{drive_item_id} | |
| Notion (pages) | Notion page UUID directly | |
| Notion (attachments) | Notion block UUID | |
| GitHub (PRs/Issues) | html_url of the PR or issue | |
| RDBMS | {db_type}:{database}:{id_column_value}, or MD5(content) if no id column |
SharePoint namespaces by drive ID because Graph API driveItem.id values are only unique within a single drive — a site can expose multiple document libraries .
Notion appends the page UUID to the semantic identifier to disambiguate pages with duplicate names .
RDBMS defaults to an MD5 hash of the serialized row content when no id_column is configured , making IDs unstable if row content changes. Always configure id_column for RDBMS connectors when possible.
Fingerprint-Based Change Detection#
The FingerprintConnector Interface#
FingerprintConnector is the interface for sources that can enumerate their keyspace cheaply via metadata-only calls — without downloading object bodies. It requires two methods:
list_keys()— yieldsKeyRecord(key, fingerprint, deleted)for every object in the sourceget_value(key)— downloads and returns a fully-populatedDocumentfor a single key; called only when the fingerprint has changed
BlobStorageConnector is the only current FingerprintConnector implementation . It uses S3's list_objects_v2 (which returns ETag in the listing without a GetObject call) to populate KeyRecord.fingerprint cheaply .
Fingerprint Format#
Blob storage normalizes the S3 ETag (which varies between single-part MD5 and multipart <md5>-<n> formats) to a uniform 32-char hex string via _normalize_etag() using xxhash.xxh128. This ensures equality comparison works regardless of upload method or provider quirks.
The Document.fingerprint field is an optional str . When set, the orchestrator persists it as content_hash and skips recomputing xxhash128(blob) after download.
Orchestration: _fingerprint_filtered_generator#
The sync worker _BlobLikeBase._fingerprint_filtered_generator() orchestrates the bypass logic:
- Pre-loads
{doc_id: content_hash}from the database for all existing documents in the KB from this connector - Iterates
connector.list_keys()— metadata only, no downloads - Resolves the stored fingerprint against both the legacy format (
hash128(connector_id:key)) and the current format (hash128(kb_id:connector_id:key)) for backward compatibility - Skips
get_value()whenkey_record.fingerprint == stored - Fetches via
get_value()only for new or changed objects - Logs bypass/fetch/fail counts; uses
WARNINGlevel if any fetch failed
The fingerprint path is disabled on explicit full reindex (task["reindex"] == "1"), which forces all objects through load_from_state() .
Incremental Sync (Non-Fingerprint Connectors)#
Connectors that don't implement FingerprintConnector use time-based incremental sync:
- Blob — when fingerprint path is unavailable (e.g. full reindex), falls back to filtering by
LastModifiedwithin a(start, end]window ; SharePoint similarly filters bylastModifiedDateTime - Notion — uses Notion's search API sorted by
last_edited_timedescending; stops when page timestamps fall beforestart - GitHub — checkpoint-based pagination (
GithubConnectorCheckpoint) with per-repo stage tracking; stops whenpr.updated_at <= start - RDBMS — optional
timestamp_columncursor;prepare_sync_state()snapshots the currentMAX(timestamp_column)before fetching, andpersist_sync_state()writes it back to the connector config ; withouttimestamp_column, falls back to full table scan
Key Source Files#
| File | Purpose |
|---|---|
common/data_source/interfaces.py | FingerprintConnector, LoadConnector, PollConnector, CheckpointedConnector ABCs |
common/data_source/models.py | Document, KeyRecord, SlimDocument, ConnectorCheckpoint models |
common/data_source/blob_connector.py | BlobStorageConnector — FingerprintConnector with ETag normalization |
common/data_source/sharepoint_connector.py | SharePointConnector — checkpoint-based, {drive_id}:{item_id} IDs |
common/data_source/notion_connector.py | NotionConnector — page UUID IDs, time-window polling |
common/data_source/github/connector.py | GithubConnector — HTML URL IDs, per-repo checkpointed pagination |
common/data_source/rdbms_connector.py | RDBMSConnector — cursor-based incremental sync, MD5 fallback IDs |
rag/svr/sync_data_source.py | Sync orchestration, _fingerprint_filtered_generator |