Incremental Graph Updates in AutoGraph
Insert, delete, and update individual documents in an existing AutoGraph knowledge graph without rebuilding the corpus
Incremental Graph Updates (IGU) keep a knowledge graph up-to-date after it has been built. You can add new documents, remove obsolete ones, and replace documents whose content has changed, without running the corpus build, the RAG Strategizer, and a full orchestration pass again.
IGU updates all three layers. In Layers 1 and 2, it maintains the corpus graph with its sources, similarity edges, and cluster membership. In Layer 3, it adds or removes the knowledge graph data, such as documents, chunks, entities, communities, and relationships. Existing clusters and strategy profiles are kept, and a new document joins the cluster closest to it, so the whole category does not have to be clustered again.
Adding to Layer 3 is the Importer’s job. Removing from it is not. AutoGraph deletes knowledge graph data itself, with AQL queries, and only involves the Importer when new content has to be extracted, embedded, and clustered:
| Operation | Layers 1 and 2 | Layer 3 |
|---|---|---|
| Insert | AutoGraph, reported in the response | The Importer, through a targeted orchestration that you start afterwards |
| Delete | AutoGraph, reported in the response | AutoGraph, in the same call, before Layers 1 and 2 |
| Update | AutoGraph, asynchronous | The old data: AutoGraph, in the same run. The new version: the Importer, through a targeted orchestration |
| Recluster | Not touched | The Importer, rebuilding the communities of the partition |
An update is a delete followed by an insert, which is why its Layer 3 work is split between the two services in exactly that way.
How you track an operation follows from the table. What AutoGraph does itself is reported by the call that did it. What the Importer does runs in the background, so you start it with an orchestration call and poll until it is finished.
For everyday document changes, this is much cheaper and faster than a rebuild, because only the documents that actually changed are processed.
Supported operations
| Operation | Endpoint | Purpose |
|---|---|---|
| Insert | POST /v1/graph/insert | Add a document that is not in the graph yet |
| Delete | POST /v1/graph/delete | Remove a document and its data |
| Update | POST /v1/graph/update | Replace the content of a document that already exists |
| Recluster | POST /v1/graph/recluster | Rebuild the Layer 3 communities of a FullGraphRAG partition that has drifted |
Insert, delete, and update work on documents and start in Layers 1 and 2, as described above. Reclustering is different: it takes Layer 3 partitions directly, schedules the Importer work for them, and resets the divergence values if the job succeeds.
This page explains the concepts: when to use IGU, how it compares to a rebuild, and how partition divergence is measured. For the requests and responses of each endpoint, see the Graph Operations reference.
When to use IGU
Use IGU if all of the following is true:
- The initial corpus build has finished successfully, and usually the RAG Strategizer and orchestration have run as well.
- You want to add, remove, or replace documents in an existing category. Every endpoint takes a batch, so this is not limited to one document per call.
- The change is small compared to what the category already holds.
- The cluster topology is still valid. You are not redesigning categories, and you do not need to compute the similarity and clustering of a whole category again.
When not to use IGU
| Situation | Use instead |
|---|---|
| No corpus graph exists yet | The standard workflow |
| Adding an entirely new category | POST /v1/corpus/builds with the new category in categories and incremental: false |
| Clean rebuild of a category, for example because of wrong embeddings, bad clusters, or files that are replaced as a whole | DELETE /v1/projects/{project}/categories/{category}, then a corpus build, the RAG Strategizer, and an orchestration for that category. A build with incremental: false over a category that already exists is rejected with REBUILD_NOT_ALLOWED |
| Adding documents in bulk to an existing category, that is, a batch that is large in relation to what the category already holds | POST /v1/corpus/builds with that category in categories and incremental: true. This keeps the existing collections and adds the new documents to them |
| You only need vectors on an existing collection | POST /v1/embed-field-in-collection |
Rule of thumb: Use IGU for changes that are small in relation to the category, whether that is one document or a batch of them, an incremental corpus build for bulk additions, and a corpus build for a new category or a clean category rebuild.
Prerequisites
- Arango Contextual Data Platform 4.1.0, where IGU is only available through the HTTP API.
- An AutoGraph project with a corpus graph that has already been built. Typically, the RAG Strategizer and orchestration have run as well.
- The project was built through the
File Manager,
so that every document in the project has a
file_id. - The documents you want to change belong to existing categories.
Full rebuild vs. IGU
| Full rebuild | IGU | |
|---|---|---|
| How | Delete the category, then POST /v1/corpus/builds with the category in categories, followed by the RAG Strategizer and orchestration | POST /v1/graph/insert, /delete, or /update, then a targeted orchestration for Layer 3 where one is needed. No Strategizer run. Optionally /recluster if the divergence is high |
| Scope | The entire category. Similarity, clustering, and the related graph data are wiped and rebuilt | Individual documents in an existing category |
| Clusters and strategies | Computed again for the processed category | Existing clusters and rags profiles are kept. A new document joins the closest cluster at Layer 2 and inherits that cluster’s strategy profile, so the RAG Strategizer never runs again |
| Layer 3 | Orchestrated again for the affected partitions after the Strategizer | Targeted orchestration for inserted and updated files, scoped to their file_ids. Deletions need no orchestration, they clean up Layer 3 in the same call |
| Cost and time | Higher. Full extraction, embedding, and clustering, usually followed by a Strategizer and Importer run | Lower. Only the changed documents are processed |
| Use if | Embeddings or clusters are wrong, files are replaced as a whole, or the category topology has to be reset | You regularly add, remove, or replace documents and the cluster topology is still valid |
Insert vs. update
| Insert | Update | |
|---|---|---|
| Use if | The document is not in the graph yet | The document already exists and you want to replace its content |
| Effect | Adds the source and its embedding, assigns the closest cluster, and updates Layers 1 and 2 | Deletes the old graph data, waits for the Layer 3 cleanup, and then adds the new version to Layers 1 and 2 |
| Layer 3 | Run a targeted orchestration afterwards, so that the knowledge graph includes the new document | Run a targeted orchestration afterwards for the new version |
| Wrong choice | Using insert for a doc_name or file_id that already exists creates duplicates and conflicts | Using update for a document that is not in the graph fails the validation |
Workflow
flowchart TD
A["Corpus graph already built"] --> B["Insert / Delete / Update\n(Layers 1-2)"]
B --> C["Targeted orchestration\nfile_ids\n(Layer 3)"]
C --> D{"needs_reclustering\ntrue?"}
D -->|no| E["Done"]
D -->|yes| F["POST /v1/graph/recluster\n(your decision)"]
F --> G["Communities refreshed\ndivergence reset to 0"]- Change the documents. Call insert, delete, or update, depending on what changed.
- Build Layer 3. After an insert or a successful update, run a
targeted orchestration with
the returned
file_id, so that the knowledge graph contains the new content. AutoGraph works out which strategized clusters hold those ids, so you do not name a partition. Both insert and update take File Manager input only, so every changed document has afile_idyou can target with. See Identifying documents for Layer 3. A delete needs no orchestration, because it has already removed its Layer 3 data. - Check the divergence. On a FullGraphRAG partition, a new
divergence_scoreis calculated once Layer 3 reflects the change, andneeds_reclusteringis set if the score is above the partition’s threshold. Insert and update responses do not carry the score, so read it fromGET /v1/orchestrate/{orchestration_id}after step 2, see Where to read the score. VectorRAG partitions have nothing to measure and are never flagged, so this step and the next one do not apply to them. - Recluster if you want to. If the flag is
trueand you think the refresh is worth the cost, call recluster with the affectedrag_partition_idvalues, at most five per request. Reclusterings run one at a time and hold the service-wide write slot for the whole run, so plan them like a maintenance window. Confirm the outcome on the partition’sragsnode:needs_reclusteringis cleared andlast_reclustered_atis set only if it really ran.
Identifying documents for Layer 3
A targeted orchestration identifies documents by file_id alone. doc_name does
not work here, and it never has to:
insert and
update both require a File Manager
file_id for every document, so the id you send is the id you pass on to the
orchestration. IDs have the form rag-input-{base64url(db:path)} and refer to a
File Manager path, which is why the prerequisites ask for a
project built through the File Manager. Upload a document with
POST /_platform/filemanager/_db/{database}/rag-input
and pass the returned ID.
After an insert or an update, send the file_ids of the changed documents,
together with the project, which is required. Non-empty file_ids is what
keeps an already imported partition eligible, because it bypasses the filter
that orchestration applies otherwise.
Sending categories alone does not bypass that filter. Orchestration then only
builds the partitions that are not in the {project}_kg knowledge graph yet,
which skips exactly the partitions that your insert or update touched. If
nothing else is stale, the request is rejected with a 409 and a
Nothing to orchestrate message, see
Telling the three 409 responses apart.
Partition divergence and reclustering
After every insert, delete, and update, AutoGraph measures how far each affected
FullGraphRAG partition in Layer 3 has drifted from the state it was in when
it was last clustered with the Leiden algorithm. The result is a
divergence_score. It is stored in the partition’s rags strategy profile.
Where you can read it back depends on the operation, see Where to read the
score.
Everything in this section applies to FullGraphRAG partitions only.
The divergence is only a signal. AutoGraph never starts a reclustering on its
own. If the score gets above the partition’s threshold, AutoGraph sets
needs_reclustering: true and leaves the decision to you.
Entities, and reclustering
rebuilds its Communities and community edges. VectorRAG partitions
(strategy_type: VectorRAG, rag_partition_id ending in _b) have neither
collection, see Layer 3 collections. Their score
therefore stays at 0, needs_reclustering is never set, and there is nothing
for a reclustering to rebuild. Insert, delete, and update work on both kinds of
partition.How the score is calculated
The stored score is the higher one of two values:
divergence_score = max(gross_churn_score, multi_batch_score)
needs_reclustering = (divergence_score > divergence_threshold)
The divergence_threshold is stored per partition on the rags profile and
is 0.25 (25%) in this release. It is not configurable through the API:
no request field sets it, so every partition falls through to the default. The
only way to change it is to edit the rags document in ArangoDB by hand. A score
that is equal to the threshold does not set the flag, only a higher score does.
Gross churn score
gross_churn_score = cumulative_churn / baseline_entity_count
baseline_entity_countis the number of distinct entity names at the time of the last successful clustering or reclustering. The first time the score is measured after a partition is built, the current count becomes the baseline and the score starts at0.cumulative_churnis the total number of entities that have been added and deleted by all inserts, deletes, and updates since that baseline. The churn is gross, not net. An update that removes 100 entities and adds 100 new ones therefore adds about 200 to the total, not 0.
For example, with a baseline of 1000 entities, deleting 100 entities and
then adding 100 gives a cumulative_churn of 200 and thus a
gross_churn_score of 0.20.
Multi-batch score
If a partition has taken several incremental imports without being
consolidated, the same entities can exist multiple times across the import
batches. AutoGraph groups the entities by import_number, uses the largest
batch as the baseline, and counts everything outside of it as changed:
multi_batch_score = (total_entities - largest_batch) / total_entities
A partition with a single batch, or with no entities at all, scores 0 here.
Batch sizes of [500, 300, 200], for example, give
(1000 - 500) / 1000 = 0.50.
Combined example
If the gross churn is 0.20 and the multi-batch value is 0.50, then the
divergence_score is 0.50. With the threshold of 0.25,
needs_reclustering is set to true.
Where the values are stored
The divergence values are stored in the partition’s rags strategy profile:
| Field | Meaning |
|---|---|
divergence_score | The current score, calculated as described above |
divergence_threshold | The threshold for this partition. Always 0.25, as no API sets it |
needs_reclustering | true as soon as the score is above the threshold |
last_reclustered_at | When the partition was last clustered or reclustered successfully, as epoch seconds. This is also when the current baseline was taken |
Divergence lifecycle
| Event | Effect on the divergence values |
|---|---|
| First measurement after a build | The current entity count becomes the baseline, the score is 0, and the flag is false |
| Insert, delete, or update, once Layer 3 reflects the change | The score is calculated again, and the flag is set if the score is above the threshold |
Successful POST /v1/graph/recluster | The score is reset to 0, the churn is cleared, a new baseline is taken, the flag is cleared, and last_reclustered_at is set |
| Failed, deferred, or incomplete reclustering | The score and the flag stay as they are, so that you can try again later. A partition that never got the write slot is left untouched in exactly the same way |
Where to read the score
A score is only meaningful once Layer 3 reflects the change, so insert and update do not report one at all. Their responses are produced while the work is still in Layers 1 and 2, before a targeted orchestration has created the entities the score would be measured against. Rather than return a value that is wrong by construction, AutoGraph leaves the field off.
That leaves three places to read it:
| Where | What you get | Notes |
|---|---|---|
GET /v1/orchestrate/{orchestration_id}, per entry of jobs | The authoritative score for each partition the run touched | This is the value to act on after an insert or an update. Held in memory only: a new POST /v1/orchestrate evicts the previous run, and an unknown or evicted id returns 404 |
POST /v1/graph/delete, per file in results | The score after the deletion | Stamped only if overall_status is COMMITTED. A deletion that ends in ROLLED_BACK or FAILED writes no score |
The partition’s rags strategy profile | The durable state, see Where the values are stored | Survives eviction. Read it here when the orchestration status is gone |
A delete can report its score directly because it removes the Layer 3 data itself, before it returns. There is no import to schedule afterwards, so nothing is still pending when the score is taken.
Next steps
- Graph Operations: The requests
and responses of
/v1/graph/insert,/delete,/update, and/recluster, as well as targeted orchestration withfile_ids - Design Guide: How categories, layers, and partitions fit together
- Corpus Build: Incremental builds for new categories and bulk additions
- Importer Incremental Updates: What the Importer does for Layer 3, and its reclustering endpoint
- Error Handling: HTTP codes and general troubleshooting
