What is a temporal knowledge graph?

Short answer: It attaches validity periods to relationships so past and present facts stay distinguishable.

A timeless edge treats every connection as still true, which fails when roles and partnerships change. Giving a relationship start and end times records when it held. Ending a relationship with a date preserves history; deleting it erases the ability to answer what used to be true. Queries filter for current edges or ask as-of a past moment. Engram’s structured properties can model these time-bound links.

The previous chapter treated a knowledge graph’s relationships as though they simply exist, connected once and available for traversal from then on. Real relationships rarely work that way. A role changes, a partnership ends, a title gets replaced by a new one, and a graph that only records whether two entities are connected, without also recording when that connection actually held, will eventually assert things that used to be true as though they still are.

What Actually Goes Wrong When a Knowledge Graph Ignores Time Entirely?

A graph edge that simply states one entity is connected to another, with no sense of when that connection started or whether it has since ended, treats every relationship as permanent by default. This works fine for genuinely permanent facts, but most interesting relationships in a real, evolving domain aren’t permanent at all, they hold for a specific stretch of time and then get superseded by something else. A graph that can’t distinguish a currently active relationship from one that used to be true will eventually surface an outdated connection with exactly the same confidence as a current one, leading a system, or a person relying on it, toward a conclusion that’s no longer accurate.

What Does It Actually Mean to Give a Relationship a Validity Period?

A temporal knowledge graph attaches a start and, where applicable, an end to each relationship, marking the specific window of time during which that connection actually held. A person’s employment at a given company becomes a relationship with a start date, and if that employment has ended, an end date as well, rather than a bare, timeless assertion that the person works there. This lets a graph traversal filter not just for what’s connected, but for what was connected at a specific point in time, or what remains connected as of right now, a genuinely different and more precise kind of question than plain connectivity ever supported.

Why Does This Matter More for Relationships Than It Might for the Facts Those Relationships Sit Between?

Reconciliation, covered elsewhere in this knowledge base, already handles superseding a fact as new information arrives, an old preference getting replaced by an updated one. Relationships face the same challenge but with an added wrinkle: a relationship connects two things, and either side of that connection might independently change over time, meaning the relationship itself needs its own explicit lifespan rather than simply inheriting freshness from whichever entity happens to be tracked more carefully. A person can leave one role and start another entirely separate one, and a graph needs to represent both relationships accurately, one closed and one active, rather than quietly overwriting the first with the second as though only one could ever have existed.

How Does Recording When a Relationship Ended Differ from Simply Deleting It?

Deleting an outdated relationship outright destroys the historical record that the connection ever existed, which matters considerably for any question that genuinely concerns the past rather than only the present. Recording an end date instead keeps the relationship fully intact as history, simply marking that it’s no longer active, so a query asking what used to be true can still be answered accurately even after that relationship has ended. This distinction matters enormously for any domain where past state carries real value, understanding a trajectory, an audit trail, or a sequence of changes over time, rather than only ever caring about the present moment in isolation.

Does Adding This Temporal Dimension Meaningfully Complicate How a Graph Actually Gets Queried?

It adds a genuine dimension a query has to account for, but the added complexity is manageable once the underlying data actually carries validity periods explicitly. A query asking about current state simply filters for relationships with no end date, or an end date still in the future, while a query asking about historical state instead filters for relationships whose validity window actually overlapped some specific point in the past. The complexity lives mainly in making sure every relationship consistently records its own validity window at the point it’s captured, rather than in the querying itself, which becomes a fairly ordinary filtering exercise once that discipline is in place.

How Does Weaviate Engram’s Underlying Structured Properties Let a System Model This Kind of Time-Bound Relationship?

Weaviate Engram stores memories with structured, filterable date properties alongside their content, letting a relationship carry an explicit validity window rather than being treated as permanently, timelessly true. Consider an executive search firm’s candidate-and-client relationship tracker, following consultants as they move between client organizations over the course of long, multi-year professional relationships:

from engram import EngramClient
from datetime import datetime, timezone

client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])

client.memories.add(
    "This candidate served as VP of Operations at the client organization from March 2019 through August 2023, before departing to become COO at a competing firm.",
    properties={
        "candidate_id": "candidate-8842",
        "relationship_start": datetime(2019, 3, 1, tzinfo=timezone.utc).isoformat(),
        "relationship_end": datetime(2023, 8, 1, tzinfo=timezone.utc).isoformat(),
    },
)

A recruiter later researching this candidate’s current standing needs to distinguish this closed relationship from whatever role the candidate holds now, exactly the distinction an explicit end date makes possible:

current_role = client.memories.search(
    query="What is this candidate's current role and employer?",
    properties={"candidate_id": "candidate-8842"},
)

history = client.memories.search(
    query="What was this candidate's employment history at the client organization?",
    properties={"candidate_id": "candidate-8842"},
)

Because the relationship carries its own explicit start and end rather than being recorded as a bare, undated connection, a recruiter can reliably distinguish the candidate’s past role from their current one, and can still answer detailed historical questions about that closed relationship without it ever being mistaken for something still active. This is exactly the value a temporal knowledge graph delivers over a graph that only tracks whether entities are connected: the difference between confidently stating what used to be true and confidently stating what actually is true right now.

Temporal knowledge graphs keep relationships honest about when they actually held. The facts and relationships populating any of these structures, whether temporal or not, still have to come from somewhere in the first place, extracted from whatever raw, messy conversation or data a system actually receives. Our next chapter, What is fact extraction for memory?, takes up exactly that extraction process.