FastPathPreview
|
This algorithm is only available in Aura Graph Analytics. |
Glossary
- Directed
-
Directed trait. The algorithm is well-defined on a directed graph.
- Directed
-
Directed trait. The algorithm ignores the direction of the graph.
- Directed
-
Directed trait. The algorithm does not run on a directed graph.
- Undirected
-
Undirected trait. The algorithm is well-defined on an undirected graph.
- Undirected
-
Undirected trait. The algorithm ignores the undirectedness of the graph.
- Heterogeneous nodes
-
Heterogeneous nodes fully supported. The algorithm has the ability to distinguish between nodes of different types.
- Heterogeneous nodes
-
Heterogeneous nodes allowed. The algorithm treats all selected nodes similarly regardless of their label.
- Heterogeneous relationships
-
Heterogeneous relationships fully supported. The algorithm has the ability to distinguish between relationships of different types.
- Heterogeneous relationships
-
Heterogeneous relationships allowed. The algorithm treats all selected relationships similarly regardless of their type.
- Weighted relationships
-
Weighted trait. The algorithm supports a relationship property to be used as weight, specified via the relationshipWeightProperty configuration parameter.
- Weighted relationships
-
Weighted trait. The algorithm treats each relationship as equally important, discarding the value of any relationship weight.
- Node properties
-
Node properties trait. The algorithm makes use of node properties.
Introduction
FastPath is a light-weight path embedding algorithm for temporal graphs. It computes vector embeddings from event sequences, which can be used in machine learning tasks such as customer journey analysis. It is an adaptation of FastRP, sharing its qualities in dimensionality reduction.
Embeddings computed by FastPath are invariant to absolute timestamps, relying instead on event timings relative to a given observation time of their path. This allows for accurate comparison of paths occurring at different points in time.
Embeddings are computed as a sum of individual event contributions, with more significance assigned to more recent events. Each path is considered independently, which allows for computing embeddings in batches or incrementally, staying compatible with those computed before.
Input
An event sequence consists of a base node with which the embedding will be associated, and one or more event nodes tied to the base node. The input graph may contain an arbitrary number of such event sequences.
There are two supported graph schemas that encode the event sequences.
Event elapsed time
The observation time for an event sequence is given as a property of the base node, or as a parameter applied to all event sequences.
Event times are defined by a property of the event node, or by the node’s position in the event sequence, counted as the number of hops past the first event.
Event elapsed times are then defined as the observation time subtracted by the event time. Only events occurring before the observation time (i.e. with an event time strictly lower than the observation time) will contribute to resulting embeddings.
Event information
An event’s contribution to the resulting embedding depends on the event elapsed time, as well as information tied to the event node. This information can be a combination of three things
-
categorical properties
-
relationships to context nodes
-
floating point feature vectors
Events having both similar elapsed times and similar information will have similar contributions to the resulting embeddings of their respective paths. If either the elapsed time or information differs significantly, their contributions will on average be orthogonal.
What constitutes a significant difference in elapsed time depends on the grid settings and time smoothing.
| FastPath requires the feature enabled for your Neo4j Aura project. |
Considerations
Graph schema and relationship configuration
The algorithm supports two different schemas for connecting base nodes to event nodes.
-
To use the first schema configuration you provide a
firstRelationshipTypeand anextRelationshipType;eventNodeTimePropertyis optional. With this configuration each base and event node is assumed to be part of a path of the pattern:(:baseNodeLabel)-[:firstRelationshipType]-(:eventNodeLabel)-[:nextRelationshipType]-…-[:nextRelationshipType]→(:eventNodeLabel) -
To use the second schema configuration, you provide only a
eventNodeTimeProperty. It is then assumed that each base node has outgoing relationships to each of its event nodes:(:baseNodeLabel)-[:]→(:eventNodeLabel)
Optionally, the schema can also contain a node label called contextNodeLabel, see Event input features below.
Defining event timestamps
There are two ways of specifying timestamps for event nodes.
The first way is to provide a eventNodeTimeProperty, in which case each event node must hold a property of that name representing a timestamp.
If however, a nextRelationshipType is provided, eventNodeTimeProperty does not have to be provided.
In that case, time stamps are generated in an intuitive way depicted in the picture below.
The length of the nextRelationshipType path to an event defines its timestamp.
The first event node in a base node’s event chain, which is connected via a firstRelationshipType relationship from the base node, will have timestamp 0.
The next event node, accessed via a nextRelationshipType relationship from the first event node, will have timestamp 1, and so on.
You can still provide a eventNodeTimeProperty even if nextRelationshipType is used.
In that case, nextRelationshipType is not used to infer timestamps, but rather to determine which base node an event node belongs to.
Event input features
An event’s feature representation can be impacted by three different input sources. They are independent of each other and can be used both together and separately. The event feature vector is a sum over all input sources that are enabled.
-
To enable the Context nodes input source you provide a
contextNodeLabel. In this case it is assumed that there may be outgoing relationships from event nodes to context nodes, i.e., the pattern:
(:eventNodeLabel)-[:]→(:contextNodeLabel) -
To enable the Event feature vector properties input source you provide
eventNodeFeatureVectorProperty. This should be the name of a vector property present on all event nodes. -
To enable the Categorical event properties input source you provide
eventNodeCategoricalProperties. This should be the name of a property that holds integers representing categories or lists of such integers. The property must be present on all event nodes.
Grid of random vectors
Event contributions to final embeddings are sourced from randomly generated vectors arranged in a grid.
The first dimension of this grid is time, containing a number of columns equal to numTimeAnchors, evenly distributed from 0 to lookbackHorizon.
Secondly, each categorical event property, each context node, and each position of the event feature space is assigned its own row in the grid.
Each cell in the grid is then assigned a randomly generated vector of size dimension.
An event’s contribution to the final embedding is then an aggregation of vectors from rows matching the event information, and columns in the vicinity of the event elapsed time. How many columns are considered is dependent on the smoothingWindow.
Time smoothing
If smoothingRate is large, only a small amount of smoothing is applied and events that are even a small time apart (enough to be closest to different grid points) will generally have very different embeddings.
If smoothingWindow is 0, the effect is similar to having a large smoothingRate.
On the other hand, if smoothingWindow is large in relation to numTimeAnchors, and simultaneously smoothingRate is small, identical events will have similar embeddings even when their timestamps differ a lot.
Tuning parameters
In general, tuning parameters is very dependent on the specific dataset.
Embedding dimension
The embeddingDimension parameter controls the output dimension of the embeddings.
A larger dimension captures more information but increases memory and computation time.
A smaller dimension is faster but may encode the input features and event history insufficiently.
Time grid
numTimeAnchors defines the number of points in the time grid; the elapsed time from an event to the output time is rounded to this grid.
If set to 1, timestamps of events have no effect.
lookbackHorizon is the maximum age of events, relative to the output time, that are considered for the embedding; older events are discarded.
Smoothing
smoothingRate controls how fast expected similarity of events decays as their time-distance increases.
smoothingWindow widens the aggregation window to up to 2*smoothingWindow + 1 grid times.
A large smoothingWindow combined with a small smoothingRate makes identical events similar even when their timestamps differ a lot.
Syntax
This section covers the syntax used to execute the FastPath algorithm.
CALL gds.fastPath.stream(
graphName: String,
configuration: Map
) YIELD
nodeId: Integer,
embedding: Vector of FLOAT32
| Name | Type | Default | Optional | Description |
|---|---|---|---|---|
graphName |
String |
|
no |
The name of a graph stored in the catalog. |
configuration |
Map |
|
yes |
Configuration for algorithm-specifics and/or graph filtering. |
| Name | Type | Default | Optional | Description |
|---|---|---|---|---|
baseNodeLabel |
String |
|
no |
Node label for which output embeddings are desired. |
eventNodeLabel |
String |
|
no |
Node label of events related to base nodes. |
embeddingDimension |
Integer |
|
no |
The output dimension of the embeddings. Must be at least 1. |
numTimeAnchors |
Integer |
|
no |
The number of times in the time grid. Elapsed time from event to output time is rounded to this grid. If set to 1, timestamps of events have no effect. Must be at least 1. |
lookbackHorizon |
Integer |
|
no |
The maximum age of events, relative to the output time, that are considered for the embedding. Must be at least 1. |
observationTime |
Float |
|
yes |
The timestamp at which embeddings should be produced. Events at this timestamp or later are not processed. Exactly one of |
baseNodeObservationTimeProperty |
String |
|
yes |
Name of a node property on base nodes which holds a number indicating for which timestamp an output embedding should be produced. Exactly one of |
eventNodeTimeProperty |
String |
|
yes |
Name of a node property representing time on the event nodes. May be int or float. Exactly one of |
nextRelationshipType |
String |
|
yes |
Name of a relationship type between event nodes, indicating the order of events. Must be specified together with |
firstRelationshipType |
String |
|
yes |
Name of a relationship type from base nodes to event nodes, indicating the first event for each base node. Must be specified together with |
contextNodeLabel |
String |
|
yes |
Node label of context nodes that describe events. |
eventNodeFeatureVectorProperty |
String |
|
yes |
Name of a node property on event nodes which holds numerical features in vector form. |
eventNodeCategoricalProperties |
List of String |
|
yes |
Names of node properties on event nodes which hold categorical values or lists of categorical values. |
eventNodeIgnoredCategory |
Integer |
|
yes |
A category value representing that a category is missing; ignored when constructing the event embedding. |
relationshipTypes |
List of String |
|
yes |
The relationship types to include in the projection FastPath operates on. Defaults to all relationship types. |
smoothingRate |
Float |
|
yes |
Controls how fast expected similarity of events decays as their time-distance increases. |
smoothingWindow |
Integer |
|
yes |
Event embeddings are aggregated over a window containing up to |
decayRate |
Float |
|
yes |
Coefficient controlling the speed of decay of influence of older events. |
randomSeed |
Integer |
|
yes |
A random seed used for all randomness in computing the embeddings. |
jobId |
String |
|
yes |
An ID to more easily track the algorithm’s progress. |
| Name | Type | Description |
|---|---|---|
|
Integer |
The Neo4j node ID. |
|
Vector of FLOAT32 |
The computed FastPath node embedding |
CALL gds.fastPath.mutate(
graphName: String,
configuration: Map
)
YIELD
nodeCount: Integer,
nodePropertiesWritten: Integer,
preProcessingMillis: Integer,
computeMillis: Integer,
mutateMillis: Integer,
configuration: Map
| Name | Type | Default | Optional | Description |
|---|---|---|---|---|
graphName |
String |
|
no |
The name of a graph stored in the catalog. |
configuration |
Map |
|
yes |
Configuration for algorithm-specifics and/or graph filtering. |
| Name | Type | Default | Optional | Description |
|---|---|---|---|---|
baseNodeLabel |
String |
|
no |
Node label for which output embeddings are desired. |
eventNodeLabel |
String |
|
no |
Node label of events related to base nodes. |
embeddingDimension |
Integer |
|
no |
The output dimension of the embeddings. Must be at least 1. |
numTimeAnchors |
Integer |
|
no |
The number of times in the time grid. Elapsed time from event to output time is rounded to this grid. If set to 1, timestamps of events have no effect. Must be at least 1. |
lookbackHorizon |
Integer |
|
no |
The maximum age of events, relative to the output time, that are considered for the embedding. Must be at least 1. |
observationTime |
Float |
|
yes |
The timestamp at which embeddings should be produced. Events at this timestamp or later are not processed. Exactly one of |
baseNodeObservationTimeProperty |
String |
|
yes |
Name of a node property on base nodes which holds a number indicating for which timestamp an output embedding should be produced. Exactly one of |
eventNodeTimeProperty |
String |
|
yes |
Name of a node property representing time on the event nodes. May be int or float. Exactly one of |
nextRelationshipType |
String |
|
yes |
Name of a relationship type between event nodes, indicating the order of events. Must be specified together with |
firstRelationshipType |
String |
|
yes |
Name of a relationship type from base nodes to event nodes, indicating the first event for each base node. Must be specified together with |
contextNodeLabel |
String |
|
yes |
Node label of context nodes that describe events. |
eventNodeFeatureVectorProperty |
String |
|
yes |
Name of a node property on event nodes which holds numerical features in vector form. |
eventNodeCategoricalProperties |
List of String |
|
yes |
Names of node properties on event nodes which hold categorical values or lists of categorical values. |
eventNodeIgnoredCategory |
Integer |
|
yes |
A category value representing that a category is missing; ignored when constructing the event embedding. |
relationshipTypes |
List of String |
|
yes |
The relationship types to include in the projection FastPath operates on. Defaults to all relationship types. |
smoothingRate |
Float |
|
yes |
Controls how fast expected similarity of events decays as their time-distance increases. |
smoothingWindow |
Integer |
|
yes |
Event embeddings are aggregated over a window containing up to |
decayRate |
Float |
|
yes |
Coefficient controlling the speed of decay of influence of older events. |
randomSeed |
Integer |
|
yes |
A random seed used for all randomness in computing the embeddings. |
jobId |
String |
|
yes |
An ID to more easily track the algorithm’s progress. |
mutateProperty |
String |
|
no |
The node property in the in-memory graph to which the embedding is written. |
| Name | Type | Description |
|---|---|---|
nodeCount |
Integer |
The number of nodes processed. |
nodePropertiesWritten |
Integer |
The number of node properties written. |
preProcessingMillis |
Integer |
Milliseconds for preprocessing data. |
computeMillis |
Integer |
Milliseconds for running the algorithm. |
mutateMillis |
Integer |
Milliseconds for writing result data back to the projected graph. |
configuration |
Map |
The configuration used for running the algorithm. |
CALL gds.fastPath.write(
graphName: String,
configuration: Map
)
YIELD
nodeCount: Integer,
nodePropertiesWritten: Integer,
preProcessingMillis: Integer,
computeMillis: Integer,
writeMillis: Integer,
configuration: Map
| Name | Type | Default | Optional | Description |
|---|---|---|---|---|
graphName |
String |
|
no |
The name of a graph stored in the catalog. |
configuration |
Map |
|
yes |
Configuration for algorithm-specifics and/or graph filtering. |
| Name | Type | Default | Optional | Description |
|---|---|---|---|---|
baseNodeLabel |
String |
|
no |
Node label for which output embeddings are desired. |
eventNodeLabel |
String |
|
no |
Node label of events related to base nodes. |
embeddingDimension |
Integer |
|
no |
The output dimension of the embeddings. Must be at least 1. |
numTimeAnchors |
Integer |
|
no |
The number of times in the time grid. Elapsed time from event to output time is rounded to this grid. If set to 1, timestamps of events have no effect. Must be at least 1. |
lookbackHorizon |
Integer |
|
no |
The maximum age of events, relative to the output time, that are considered for the embedding. Must be at least 1. |
observationTime |
Float |
|
yes |
The timestamp at which embeddings should be produced. Events at this timestamp or later are not processed. Exactly one of |
baseNodeObservationTimeProperty |
String |
|
yes |
Name of a node property on base nodes which holds a number indicating for which timestamp an output embedding should be produced. Exactly one of |
eventNodeTimeProperty |
String |
|
yes |
Name of a node property representing time on the event nodes. May be int or float. Exactly one of |
nextRelationshipType |
String |
|
yes |
Name of a relationship type between event nodes, indicating the order of events. Must be specified together with |
firstRelationshipType |
String |
|
yes |
Name of a relationship type from base nodes to event nodes, indicating the first event for each base node. Must be specified together with |
contextNodeLabel |
String |
|
yes |
Node label of context nodes that describe events. |
eventNodeFeatureVectorProperty |
String |
|
yes |
Name of a node property on event nodes which holds numerical features in vector form. |
eventNodeCategoricalProperties |
List of String |
|
yes |
Names of node properties on event nodes which hold categorical values or lists of categorical values. |
eventNodeIgnoredCategory |
Integer |
|
yes |
A category value representing that a category is missing; ignored when constructing the event embedding. |
relationshipTypes |
List of String |
|
yes |
The relationship types to include in the projection FastPath operates on. Defaults to all relationship types. |
smoothingRate |
Float |
|
yes |
Controls how fast expected similarity of events decays as their time-distance increases. |
smoothingWindow |
Integer |
|
yes |
Event embeddings are aggregated over a window containing up to |
decayRate |
Float |
|
yes |
Coefficient controlling the speed of decay of influence of older events. |
randomSeed |
Integer |
|
yes |
A random seed used for all randomness in computing the embeddings. |
jobId |
String |
|
yes |
An ID to more easily track the algorithm’s progress. |
writeProperty |
String |
|
no |
The node property in the Neo4j database to which the embedding is written |
concurrency |
Integer |
|
yes |
The number of concurrent threads used for running the algorithm. |
writeConcurrency |
Integer |
|
yes |
The number of concurrent threads used for writing the result to Neo4j. |
| Name | Type | Description |
|---|---|---|
nodeCount |
Integer |
The number of nodes processed. |
nodePropertiesWritten |
Integer |
The number of node properties written. |
preProcessingMillis |
Integer |
Milliseconds for preprocessing data. |
computeMillis |
Integer |
Milliseconds for running the algorithm. |
writeMillis |
Integer |
Milliseconds for writing result data back to Neo4j. |
configuration |
Map |
The configuration used for running the algorithm. |
Examples
|
All the examples below should be run in an empty database. The examples use Cypher projections as the norm. |
In this example we use a small graph of medical patient records.
Patient nodes are the base nodes and carry an observation_time property.
Encounter nodes are the event nodes and carry an emb feature vector and a days time property.
HAS_ENCOUNTER relationships connect each patient to their encounters.
Because FastPath is only available in Aura Graph Analytics, the graph must be projected into a GDS Session.
This is done by passing the memory parameter (and optionally sessionId) to gds.graph.project, which creates a GDS Session for the projected graph.
CREATE
(p0:Patient {observation_time: 100}),
(p1:Patient {observation_time: 200}),
(e0:Encounter {emb: [0.1, 0.2, 0.3], days: 10}),
(e1:Encounter {emb: [0.4, 0.5, 0.6], days: 50}),
(e2:Encounter {emb: [0.7, 0.8, 0.9], days: 80}),
(p0)-[:HAS_ENCOUNTER]->(e0),
(p0)-[:HAS_ENCOUNTER]->(e1),
(p1)-[:HAS_ENCOUNTER]->(e2)
MATCH (source:Patient)
OPTIONAL MATCH (source)-[r:HAS_ENCOUNTER]->(target:Encounter)
RETURN gds.graph.project(
'patients',
source,
target,
{
sourceNodeLabels: ['Patient'],
sourceNodeProperties: source { .observation_time },
targetNodeLabels: ['Encounter'],
targetNodeProperties: target { .emb, .days },
relationshipType: 'HAS_ENCOUNTER'
},
{ memory: '2GB' }
)
Stream mode
CALL gds.fastPath.stream('patients', {
baseNodeLabel: 'Patient',
eventNodeLabel: 'Encounter',
eventNodeFeatureVectorProperty: 'emb',
baseNodeObservationTimeProperty: 'observation_time',
eventNodeTimeProperty: 'days',
embeddingDimension: 32, // in reality, a higher value is recommended
numTimeAnchors: 30,
lookbackHorizon: 3650,
smoothingRate: 0.9,
smoothingWindow: 2,
decayRate: 0.0
}) YIELD nodeId, embedding
RETURN nodeId, embedding
The stream procedure returns one row per base node.
Mutate mode
CALL gds.fastPath.mutate('patients', {
baseNodeLabel: 'Patient',
eventNodeLabel: 'Encounter',
eventNodeFeatureVectorProperty: 'emb',
baseNodeObservationTimeProperty: 'observation_time',
eventNodeTimeProperty: 'days',
embeddingDimension: 32, // in reality, a higher value is recommended
numTimeAnchors: 30,
lookbackHorizon: 3650,
mutateProperty: 'fastPathEmbedding'
}) YIELD nodeCount, nodePropertiesWritten, preProcessingMillis, computeMillis, mutateMillis
RETURN nodeCount, nodePropertiesWritten, preProcessingMillis, computeMillis, mutateMillis
Write mode
CALL gds.fastPath.write('patients', {
baseNodeLabel: 'Patient',
eventNodeLabel: 'Encounter',
eventNodeFeatureVectorProperty: 'emb',
baseNodeObservationTimeProperty: 'observation_time',
eventNodeTimeProperty: 'days',
embeddingDimension: 32, // in reality, a higher value is recommended
numTimeAnchors: 30,
lookbackHorizon: 3650,
writeProperty: 'fastPathEmbedding'
}) YIELD nodeCount, nodePropertiesWritten, preProcessingMillis, computeMillis, writeMillis
RETURN nodeCount, nodePropertiesWritten, preProcessingMillis, computeMillis, writeMillis
The fastPathEmbedding property is written back to Neo4j as a native vector property and can be indexed with a vector index for downstream similarity search.
How the algorithm works
The following sections provide more detailed information about FastPath for those interested in the inner workings of the algorithm.
The breakdown of the algorithm into steps below is conceptual.
It does not reflect the actual implementation details such as the order of loops, data structures and more.
We describe how to compute the FastPath embedding for a base node b which has output time to.
The output time is computed according to one of the chosen parameters observationTime or baseNodeObservationTimeProperty.
An arbitrary event which belongs to b is denoted by e, and its time stamp is assumed to be te.
At the time to, at which we wish to compute the embedding of b, the elapsed time of e is
tel = to - te,
that is, the amount of time between the timestamp of the event and the output time of the corresponding base node.
Note that events may belong to multiple base nodes which have different output times. This implies that some computations involving an event have to be recomputed for each of its associated base nodes, but these computations are independent of each other.
-
Preprocess
Pre-process the input into a graph with base nodes, event nodes and optionally context nodes. Base and event nodes are connected and so are events and context nodes. If time stamps are not given for events, time stamps are generated by traversing event chains per base node. -
Filter relevant events
Out of the events that belong to the base nodeb, any event which has elapsed time exceedinglookbackHorizon, or any event which occurred at timetoor later, is removed. The remaining relevant events forbare calledE(b). -
Create grid
Create a grid over time, subsequently referred to as the grid. -
Generate random vectors
Sparse random vectors are generated independently per input source below, if they are selected.
For each time in the grid and input source, generate vectors as follows:-
Event feature vector properties: a vector
ri,tis generated for each dimensioniof the input event feature vectors -
Context nodes: for each context node
c, generaterc,t -
Categorical event properties: for each categorical node property
propand for each valuevof that property, initialize a random vectorrprop,v,t.
If the property value for any event is a list of categories[v1, v2, …], andvis any of these values, we initialize a random vectorr~prop,v.
-
-
Compute event node pre-embeddings
The pre-embedding for an eventeat timetis denoted byxe,tand initialized to all zeros. For all input sources below that apply, weighted sums of random vectors generated in step 4 are added toxe,t:-
Event feature vector properties:
xe,t += ∑i ri,t * inpi
whereinpis the input vector ofeandiranges over the dimensions ofinp. -
Context nodes:
xe,t += ∑c rc,t
wherecranges over all neighbors of the evente. -
Categorical event properties:
xe,t += ∑prop rprop,e.prop,t
wherepropranges over all selected categorical event properties.
Or whene.propis a list:xe,t = ∑prop ∑v in e.prop rprop,v,t
-
-
Compute event embeddings
We compute an embedding foreusing its earlier derived pre-embeddings at different times. We find the timetclin the grid which is the closest to the elapsed timetel = to - te. Then adding up tosmoothingWindowpoints in the grid on both sides oftcl, we obtain a windowWeof relevant grid times for the event. In the picture,smoothingWindow = 1andtcl=t4, thereforeWe = {t3,t4,t5}. For eachtinWewe set the weight of the grid pointtto be,
w(t) = exp(-|t - tel| * smoothingRate ) / Ze,
whereZeis the constant that ensures∑t in W_e w(t) = 1.
The embedding of the event at output timetois then
emb(e|to) = ∑t in W_e w(t) * xe,t.
This constructs time-smoothed embeddings by taking an average of a grid of pre-embeddings, or basis vectors. The purpose of the time-smoothing mechanism is to ensure that embeddings change continuously with respect to changes in elapsed time, all other factors being equal. -
Compute base node embeddings
The embedding forbis finally given by
emb(b) = ∑e in E(b) wb,e * emb(e)
where
wb,e = exp(-decayRate * (to - te))andE(b)was defined in step 2.
The figure below gives an overview of what influences event embeddings and how they flow to the embedding of a base node, based on the output time and elapsed times.