Filtering
The filter module provides filter expressions for selecting subsets of nodes and edges based on their attributes, properties, and relationships.
The filter module mirrors Raphtory's APIs. Anything you can do with temporal properties, layers, windows, or metadata can be expressed as a filter. This lets Raphtory handle filtering internally with optimised Rust code rather than requiring Python loops. If you find yourself writing a for-loop to filter entities, there's probably a filter expression that does it faster.
Filtering vs Indexing
There are two ways to apply filters:
-
Indexing (
nodes[filter]) — applies a filter once to a collection, returning the matching items as a new collection. The original graph and any relationships remain unchanged, so traversing from filtered nodes still accesses all neighbours and edges. -
.filter(expr)— creates a persistent filtered view of the graph. The filter propagates through all subsequent operations: accessing edges, neighbours, or properties only returns data that satisfies the filter condition.
Filter Classes
Raphtory provides four filter classes:
| Filter Class | Purpose |
|---|---|
filter.Graph | Time and layer filters |
filter.Node | Filter nodes by name, type, id, metadata, properties |
filter.Edge | Filter edges by layer, properties, and endpoint attributes |
filter.ExplodedEdge | Filter individual edge updates |
filter.Graph
filter.Graph supports all view functions from Graph Views. You can filter by time windows, layers, snapshots, and more.
The example shows a social network with edges added at different times across work and social layers. We filter to edges before/after a timestamp, within a time window, and on specific layers.
filter.Node
filter.Node filters nodes by their attributes and properties. You can also chain view functions (like window() or layer()) to filter properties within specific time or layer bounds.
The example creates users with metadata and salary history. We filter by name prefix, node type, metadata values, and demonstrate window() chaining to find nodes where the max salary within a time range meets a condition.
| Method | Description |
|---|---|
name() | Access node name (supports string operations) |
node_type() | Access node type |
id() | Access node ID |
metadata(key) | Access metadata |
property(key) | Access temporal properties |
filter.Edge
filter.Edge filters edges by their properties and endpoints. The src() and dst() methods let you filter based on source and destination node attributes. Like filter.Node, you can chain view functions to scope property lookups.
The example creates a graph of people and companies with relationship edges. We filter by layer + property conditions, use window() to scope temporal lookups, and filter by source/destination node types and metadata.
| Method | Description |
|---|---|
metadata(key) | Access metadata |
property(key) | Access temporal properties |
src() | Access source node attributes |
dst() | Access destination node attributes |
filter.ExplodedEdge
When you call edge.explode(), each temporal update becomes a separate item. filter.ExplodedEdge lets you filter these individual updates.
The example shows a sensor sending readings to a hub over time. Each reading has a temperature and status. After exploding the edge, we filter individual updates by their property values to find critical readings or readings above a threshold.
If all updates for an edge are filtered out, the edge itself is removed from the result.
Property Filtering
Metadata
Metadata are immutable values set on a node or edge. They don't change over time. Use metadata(key) to filter by these values.
The example below shows sensors with different locations, models, and calibration status. We filter by exact match, use is_in() to match multiple values, is_not_in() to exclude values, and contains() for substring matching. The final filter combines conditions to find calibrated sensors in priority warehouses.
Temporal Property Operations
Temporal properties store multiple values over time. Use .temporal() to access aggregation and quantifier operations that filter based on the entire history of a property, not just its current value.
The example tracks temperature readings from sensors over time, then filters using .max(), .avg(), .any(), and .all() to answer questions like "which sensors ever exceeded 30°C?" or "which sensors always stayed below 25°C?".
| Operation | Description |
|---|---|
sum() | Sum of all values |
avg() | Average of all values |
min(), max() | Minimum/maximum value |
first(), last() | First/most recent value |
all() | All values must satisfy condition |
any() | At least one value must satisfy condition |
len() | Count of updates |
Scoping with Window and Layer
When filtering by temporal properties, you can scope the lookup using window() or layer(). This is useful for questions like "which servers had high CPU usage during the incident window?" or "which edges in the work layer have been active recently?"
The pattern is filter.Node.window(start, end).property("key").temporal().aggregation(). Without a window, the filter considers the entire history. With a window, only values within that time range are used for aggregation.
The example tracks CPU usage across servers. During normal operation, usage is low. During a high-traffic window (t=4-11), some servers spike. We compare filtering with and without windows to show how scoping changes the results.
String Operations
For string-valued attributes like names and metadata, you can use string operations to match patterns. These work on name(), node_type(), and string metadata/properties.
| Operation | Description |
|---|---|
starts_with(prefix) | String starts with prefix |
ends_with(suffix) | String ends with suffix |
contains(substring) | String contains substring |
not_contains(substring) | String doesn't contain substring |
fuzzy_search(pattern, max_edits, prefix) | Fuzzy matching: max_edits = allowed character edits, prefix = required exact prefix length |
is_in([...]) | Value is in list |
is_not_in([...]) | Value is not in list |
Checking Property Existence
Use is_some() and is_none() to filter based on whether a property exists. This is useful when properties may be missing on some entities.
Combining Filters
Combine filter expressions with Python's bitwise operators:
| Operator | Meaning |
|---|---|
& | AND — both conditions must be true |
| | OR — at least one condition must be true |
~ | NOT — negates the condition |
You must use bitwise operators &, |, and ~. Python's and, or, and not keywords do not work with filter expressions.
The example creates users with admin/user types and active/inactive status. We define base filters for admin and active, then combine them to find active admins, inactive admins, and active non-admins.
The Prop Type
When filtering on properties with specific internal types, use the Prop class to create typed values for comparison. This is essential when properties are stored as types Python doesn't have natively (like u8 or f32).
| Type Constructor | Description |
|---|---|
Prop.bool(v) | Boolean |
Prop.str(v) | String |
Prop.u8(v), Prop.u16(v), Prop.u32(v), Prop.u64(v) | Unsigned integers (8, 16, 32, 64-bit) |
Prop.i32(v), Prop.i64(v) | Signed integers (32, 64-bit) |
Prop.f32(v), Prop.f64(v) | Floating point (32, 64-bit) |
Prop.list(v) | List of values |
Prop.map(v) | Dictionary/map |
Comparison operators: ==, !=, <, <=, >, >=