Knowledge Graph Versioning

Open inAnthropic

Knowledge graph versioning is a way to keep the earlier states of a knowledge graph when its facts change. With it, you can read the graph as it was, see what changed between two versions, and undo a bad change.

This page explains the common ways to do graph versioning and what each one costs. At the end, it shows how TerminusDB does it, with a short example you can run.

Try it in TerminusDB

TerminusDB is a knowledge graph database with versioning built in. For a tour of the git-like commands, see Knowledge Graph Version Control.

What is knowledge graph versioning?

A knowledge graph stores facts as links between things: "Alice works for Acme", "Acme is in Oslo". These facts change. People change jobs, a source sends a correction, a data load goes wrong.

In most databases, a change overwrites the old value. After that, nobody can say what the graph said yesterday. Versioning fixes this. Each change makes a new version, and the old versions stay.

This matters for some common jobs:

  • Audit. Show what a fact said on a given day, and who changed it.
  • Reproducible results. Run a report or train a model on a fixed version, where the numbers do not move.
  • Safe changes. Try a large change away from the live graph, check it, then make it live.
  • Recovery. Go back to a known good version after a bad import.

Four ways to version a graph

There is no single standard for this. Teams use one of these four approaches, or a mix.

1. Full snapshots

You copy the whole graph at set times, for example every night. Each copy is one version.

This is easy to understand and easy to read. But storage grows with every copy, even if only one fact changed. You also lose the changes made between two snapshots.

2. Change logs (deltas)

You store a base version, then a log of each change: which facts were added and which were removed. To read an old version, you start from the base and apply the changes up to that point.

This uses much less storage. Reading an old version can be slow if the log is long, unless the system keeps extra copies or indexes to help.

3. Timestamps on facts or named graphs

You put the time in the data itself. Each fact, or each group of facts, gets a "valid from" and "valid to" value. In RDF, people often use a named graph per version, or extra statements about each triple.

This lets you ask "what was true at time T" in a normal query. But every query must filter on time, and the data model gets more complex. It is also easy to forget the filter and mix versions by mistake.

4. A commit graph

This is how Git works. Each change is a commit. A commit points to the commit before it, and it records who made the change, when and why. A branch is a name that points to the newest commit in one line of history.

Under the hood, a commit graph usually stores deltas. On top of that, it gives you branches, diffs and merges. It is the most complete approach, but you need a store that supports it.

ApproachStorageRead an old versionBranches and mergeWho changed what
Full snapshotsHighFastNoNo
Change logsLowCan be slowNoOnly if you log it
Timestamps in the dataMediumIn the queryNoOnly if you model it
Commit graphLowFast, if the store is built for itYesYes, per commit

Snapshot vs delta: the trade-off

The main choice is between storing whole copies and storing changes.

  • Snapshots cost storage, but every version is ready to read.
  • Deltas save storage, but an old version must be built from the changes.

Most real systems mix the two. They store deltas, and from time to time they also store a combined copy. Then a read only needs to go back to the nearest combined copy, not to the start.

TerminusDB works this way. Each commit adds a delta layer with the triples it added and removed. A delta rollup combines many layers into fewer cached layers. In standard setups the rollup runs automatically, so reads stay fast as history grows. The cost is a bit of disk storage.

What a versioned knowledge graph should let you do

Keeping old versions is only the first step. To be useful, versioning should let you:

  • Query a past version with the same query language you use for live data.
  • Versioned hybrid search with both full text search (FTS) and vector search.
  • Diff two versions, and see each fact and value that changed.
  • Branch, so you can make changes away from the live graph.
  • Merge a branch back, and get a clear report if two changes conflict.
  • Clone, push and pull data products between networks across unidirectional links.
  • Roll back to an earlier version when a change was wrong.
  • See who changed what, with an author and a message on each change.

If your tool only does the first item, you have versioning but not version control. That can be enough. But if people or programs change the graph often, you will probably want the rest.

How TerminusDB versions a knowledge graph

TerminusDB uses a commit graph. Every write is an immutable commit with an author, a message and a timestamp. Branches are cheap, because a new branch shares its history with the branch it came from. You can query any branch or commit with the same API, compare two versions with a structural diff, and merge with a three-way merge.

The example below uses the HTTP API on a local TerminusDB at localhost:6363 with the default admin:root login. It is a tiny graph: one person who works for one organization.

1. Set up a small graph

Create a database, add a schema with two linked classes, and add the first facts. Each write is a commit.

Loading…

Expected output:

{
  "@type": "api:DbCreateResponse",
  "api:status": "api:success"
}
Loading…

Expected output:

[
  "Organization",
  "Person"
]
Loading…

Expected output:

[
  "Organization/acme",
  "Person/alice"
]

2. Make a branch

The branch starts with the same data as main. It shares history with main, so the data is not copied.

Loading…

Expected output:

{
  "@type": "api:BranchResponse",
  "api:status": "api:success"
}

3. Change a fact on the branch

Alice gets a new role. Only the update branch changes. main still says "Engineer".

Loading…

Expected output:

[
  "Person/alice"
]

4. Diff the two versions

The diff shows the one field that changed, with its old and new value.

Loading…

Expected output:

[
  {
    "@id": "Person/alice",
    "role": {
      "@after": "CTO",
      "@before": "Engineer",
      "@op": "SwapValue"
    }
  }
]

5. Merge, and keep the old version

Merge the branch into main. Here main has not changed since the branch was made, so main is the right merge base. If both branches had changed the same field, the merge would return HTTP 409 with a conflict report.

Loading…

Expected output:

{
  "@type": "api:ApplyResponse",
  "api:status": "api:success"
}

main now says "CTO". The old version is still there. The commit log lists each commit with its identifier, author and message:

Loading…

To read the graph as it was before the change, put a commit identifier from the log in the path, in place of branch/main:

curl -u admin:root \
  "http://localhost:6363/api/document/admin/MyDatabase/local/commit/<identifier>?id=Person/alice"

This is a normal read. TerminusDB does not rebuild the past from a log. See time travel queries for more.

When you are done, delete the demo database:

Loading…

The time travel how-to and the merge how-to show the same ideas with the TypeScript and Python clients.

When you don't need versioning

Versioning is not always worth it. You may not need it if:

  • The data is a cache or a copy that you can rebuild from the source at any time.
  • You only append new events and never change old ones. A log or time-series database may fit better.
  • Nobody needs to know what the data said in the past, and nobody reviews changes anyway.

Also keep in mind that history uses disk storage. And if a branch has many small steps that nobody needs to see, you can squash them into one commit before you merge.

Next steps

Frequently asked questions

What is knowledge graph versioning?

It is a way to keep the earlier states of a knowledge graph when its facts change. You can then read an old version, see what changed between two versions, and go back if a change was wrong.

Is knowledge graph versioning the same as version control?

Not quite. Versioning means you keep past versions. Version control adds tools to work with them, such as branches, diffs, merges and a log of who changed what. Most people who ask for versioning end up needing some of these tools too.

Should I store full snapshots or only the changes?

Snapshots are simple and fast to read, but they use a lot of storage. Deltas use little storage, but an old version must be built from the changes. Many systems mix the two, and keep deltas with a combined copy from time to time.

Can I version only the schema or ontology?

You can, but it is often not enough. When the schema changes, the data usually has to change with it. If both are in the same version, you can read old data with the schema that was valid at that time.

Does versioning make queries slower?

It depends on how the history is stored. In TerminusDB, a read at an old commit is a normal read, and delta rollup runs automatically in standard setups to keep the layer stack small. The main cost is disk storage for any later granular data or structural changes.

How do I see what changed between two versions?

You compare them with a diff. A good graph diff tells you which facts were added, removed or changed. In TerminusDB, the diff endpoint compares two branches or commits and returns the change for each document, down to the field.

Was this helpful?