How to Query Temporal Graphs Using TemporalGraphQuery.querytimerange() in Semantica

Use TemporalGraphQuery.querytimerange() with the at, after, before, start, or end parameters to filter bi-temporal knowledge graph edges by their validity intervals, then execute with .run() or .to_pandas().

The semantica-agi/semantica repository implements bi-temporal knowledge graphs where every edge carries valid_from and valid_until timestamps. To query temporal graphs and retrieve relationships active during specific time windows, developers use the TemporalGraphQuery class and its querytimerange() method, which abstracts Cypher predicate generation for temporal filtering.

TemporalGraphQuery.querytimerange() Method Overview

In semantica/kg/query.py, the TemporalGraphQuery class provides querytimerange() as the primary API for temporal filtering. The method accepts ISO-8601 timestamps and translates them into database predicates that check edge validity intervals. All parameters are optional and mutually exclusive in logical groups.

Exact Point-in-Time Queries

Use the at parameter to retrieve edges that were valid at a specific instant. This returns items where valid_from <= timestamp < valid_until, or where the timestamp falls within the stored validity interval.

from semantica.kg.query import TemporalGraphQuery

tgq = TemporalGraphQuery()
results = (
    tgq.filter_by_relation("EMPLOYED_BY")
       .querytimerange(at="2023-03-15T00:00:00Z")
       .run()
)

Open-Ended Range Queries

Use after (inclusive lower bound) or before (exclusive upper bound) to query edges valid after or before a specific time. These parameters support unbounded temporal searches without requiring an explicit end date.

tgq = TemporalGraphQuery()
df = (
    tgq.filter_by_property("status", "ACTIVE")
       .querytimerange(after="2022-06-01")
       .run()
)

Closed Range Queries

Combine start (inclusive) and end (exclusive) to define a explicit time window. The method returns edges whose validity intervals intersect with the supplied window, meaning they were active for at least part of the specified period.

tgq = TemporalGraphQuery()
df = (
    tgq.querytimerange(start="2020-01-01", end="2021-12-31")
       .to_pandas()
)

Internal Query Logic

According to semantica/kg/query.py, querytimerange() constructs a Cypher WHERE clause resembling the following pseudo-code:

WHERE
  (e.valid_from IS NULL OR e.valid_from <= $upper)
  AND (e.valid_until IS NULL OR e.valid_until >= $lower)

Here, $lower and $upper are derived from the supplied temporal arguments. If the graph stores point-in-time snapshots with only a single timestamp per edge, the logic collapses to simple equality or inequality filters. The optional timezone parameter interprets naive timestamps according to the specified tz name before query execution.

Step-by-Step Implementation Workflow

  1. Instantiate TemporalGraphQuery – Optionally inject a custom graph client from semantica/kg/methods.py to target specific database backends.

  2. Apply Domain Filters – Chain methods like filter_by_relation() or filter_by_property() to narrow the search space before applying temporal constraints.

  3. Invoke querytimerange() – Pass temporal boundaries using at, after/before, or start/end depending on your query requirements.

  4. Execute and Retrieve Results – Call .run() to return raw results or .to_pandas() to obtain a DataFrame for analysis.

Practical Code Examples

The following examples demonstrate common patterns for querying temporal graphs in Semantica:

Example 1: Retrieve relationships active on a specific date

from semantica.kg.query import TemporalGraphQuery

tgq = TemporalGraphQuery()
results = (
    tgq.filter_by_relation("EMPLOYED_BY")
       .querytimerange(at="2023-03-15T00:00:00Z")
       .run()
)
print(results)

Example 2: Find edges active within a historical window

tgq = TemporalGraphQuery()
df = (
    tgq.querytimerange(start="2020-01-01", end="2021-12-31")
       .to_pandas()
)
print(df.head())

Example 3: Combine temporal constraints with attribute filters

tgq = TemporalGraphQuery()
df = (
    tgq.filter_by_property("status", "ACTIVE")
       .querytimerange(after="2022-06-01")
       .run()
)

Key Source Files and References

Summary

  • querytimerange() is the primary method for temporal filtering in TemporalGraphQuery, implemented in semantica/kg/query.py.
  • The method supports exact point-in-time (at), open-ended ranges (after, before), and closed intervals (start/end).
  • Internally, it generates Cypher predicates that check valid_from and valid_until timestamps against supplied bounds.
  • Results can be retrieved via .run() for raw output or .to_pandas() for DataFrame analysis.

Frequently Asked Questions

What is the difference between the at and start/end parameters in querytimerange()?

The at parameter queries for edges valid at a single specific instant, checking if the timestamp falls within the edge's validity interval. The start and end parameters define a duration window, returning any edges that were active for at least part of that range through interval intersection logic.

How does querytimerange() handle edges with null validity timestamps?

The generated Cypher predicate treats null valid_from or valid_until values as unbounded. An edge with valid_from IS NULL is considered to have been valid since the beginning of time, while valid_until IS NULL indicates it remains valid indefinitely.

Can I chain querytimerange() with other filters like filter_by_relation()?

Yes, TemporalGraphQuery supports method chaining. You can combine filter_by_relation(), filter_by_property(), and querytimerange() in any order before calling .run() or .to_pandas() to execute the final query with all constraints applied.

What timestamp formats are supported when querying temporal graphs?

The method accepts ISO-8601 formatted strings (e.g., "2023-05-01T12:00:00Z"). You may also provide naive timestamps, which will be interpreted according to the optional timezone parameter passed to querytimerange().

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →