PGX 20.1.1
Documentation

Graph Mutation and Subgraphs

PGX provides several methods for mutating graph instances, as discussed here. Note that, rather than mutating the original graph directly, all of the mutating methods create a new graph/snapshot instance as the mutated version of the original graph. Refer to this document for related discussions.

All mutation and subgraph methods are defined in the PgxGraph class.

Altering Partitioned Graphs by Adding or Removing Vertex and Edge Providers

It is possible to add or remove vertex and edge providers of partitioned graphs using the alterGraph mutation APIs. Please read the dedicated documentation available at the graph alteration reference documentation.

Copying and Simplifying Graphs

The following method creates a simplified version of the graph:

PgxFuture<PgxGraph> simplifyAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, MultiEdges multiEdges, SelfEdges selfEdges, TrivialVertices trivialVertices, Mode mode, String newGraphName)

Alternatively, you may use the blocking version of the above method, which waits for the request to finish and then directly returns a simplified PgxGraph:

PgxGraph simplify(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, MultiEdges multiEdges, SelfEdges selfEdges, TrivialVertices trivialVertices, Mode mode, String newGraphName)

The first two arguments (vertexProps and edgeProps) list which properties will be copied into the newly created simplified graph instance. PGX provides convenience constants VertexProperty.ALL, EdgeProperty.ALL and VertexProperty.NONE, EdgeProperty.NONE to specify all properties or none properties to be stored, respectively.

PGX provides convenience methods for the common operation of copying all vertex and edge properties into the simplified graph instance:

PgxFuture<PgxGraph> simplifyAsync(MultiEdges multiEdges, SelfEdges selfEdges, TrivialVertices trivialVertices, Mode mode, String newGraphName)

and

PgxGraph simplify(MultiEdges multiEdges, SelfEdges selfEdges, TrivialVertices trivialVertices, Mode mode, String newGraphName)

The next three arguments determine which operations will be performed to simplify the graph.

  • multiEdges: if MultiEdges.REMOVE_MULTI_EDGES, eliminate multiple edges between a source vertex and a destination vertex — i.e., leave at most one edge between two vertices. MultiEdges.KEEP_MULTI_EDGES indicates to keep them. By default, PGX picks one edge out of the multi-edges and takes its properties. For more fine-grained control over the edge properties during simplification read advanced multi-edge handling.
  • selfEdges: if SelfEdges.REMOVE_SELF_EDGES, eliminate every edge whose source and destination are the same vertex. SelfEdges.KEEP_MULTI_EDGES indicates to keep them.
  • trivialVertices: if TrivialVertices.REMOVE_TRIVIAL_VERTICES, eliminate all the vertices that have neither incoming edges nor outgoing edges. TrivialVertices.KEEP_TRIVIAL_VERTICES indicates to keep them.

The mode argument, if set to Mode.MUTATE_IN_PLACE, requests that the mutation occurs directly on the specified graph instance without creating a new one. If set to Mode.CREATE_COPY, the method will create a new graph instance with the new name in newGraphName. If newGraphName is omitted (or null), PGX will generate a unique graph name.

The return value of this method is the simplified PgxGraph instance.

Note: The Mode.MUTATE_IN_PLACE option is only applicable if the graph is marked as mutable. Every graph is immutable by default when loaded into PGX. (PGX may share the graph instance between multiple clients as discussed here). To make a PgxGraph mutable, the client should create a private copy of the graph first, using one of the following methods:

PgxFuture<PgxGraph> cloneAsync()
PgxFuture<PgxGraph> cloneAsync(String newGraphName)
PgxFuture<PgxGraph> cloneAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, String newGraphName)

or their blocking variants:

PgxGraph clone()
PgxGraph clone(String newGraphName)
PgxGraph clone(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, String newGraphName)

As with simplify(), the user can specify optional properties of the graph to copy with vertexProps and edgeProps. If no properties are specified, all of the original graph's properties will be copied into the new graph instance. The user can specify the name of the newly created graph instance with newGraphName.

Transposing Graphs

The following method creates a transposed version of the graph:

PgxFuture<PgxGraph> transposeAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, Map<String, String> edgeLabelMapping, Mode mode, String newGraphName)

Alternatively, you may use the blocking version of the above method, which waits for the request to finish and then directly returns a transposed PgxGraph:

PgxGraph transpose(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, Map<String, String> edgeLabelMapping, Mode mode, String newGraphName)

The first two arguments (vertexProps and edgeProps) list which properties will be copied into the newly created simplified graph instance. PGX provides convenience constants VertexProperty.ALL, EdgeProperty.ALL and VertexProperty.NONE, EdgeProperty.NONE to specify all properties or none properties to be stored, respectively.

PGX provides convenience methods for the common operation of copying all vertex and edge properties into the transposed graph instance:

PgxFuture<PgxGraph> transposeAsync(Mode mode, String newGraphName)

and

PgxGraph transpose(Mode mode, String newGraphName)

PGX also provides convenience methods for copyng all edge and vertex properties using Mode as CREATE_COPY

PgxFuture<PgxGraph> transposeAsync(String newGraphName)

and

PgxGraph transpose(String newGraphName)

And convenience methods for copying all edge and vertex properties leaving newGraphName to be auto generated

PgxFuture<PgxGraph> transposeAsync(Mode mode)
//or for CREATE_COPY Mode 
PgxFuture<PgxGraph> transposeAsync()

and

PgxGraph transpose(Mode mode)
//or for CREATE_COPY Mode 
PgxGraph transpose()

The edgeLabelMapping argument can be used to rename edge labels. For example, an edge (John,Mary) labeled "fatherOf" can be transformed to be labeled "hasFather" on the transpose graph's edge (Mary,John) by passing in a map like Collections.singletonMap("fatherOf", "hasFather").

Renaming edge labels for transposed Graph

Figure: Renaming edge labels for transposed Graph

If any key in the given map does not exist as an edge label, it will be ignored.

edgeLabelMapping argument can also be an empty Map or null.

  • null: if argument is null, edge labels from source graph will be removed on transposed graph. (default behavior when using convenience methods).

  • empty Map: if argument is an empty Map, edge labels from source graph will be neither removed or renamed. Instead, it will be kept as it is in source graph.

The mode argument, if set to Mode.MUTATE_IN_PLACE, requests that the mutation occurs directly on the specified graph instance without creating a new one. If set to Mode.CREATE_COPY, the method will create a new graph instance with the new name in newGraphName. If newGraphName is omitted (or null), PGX will generate a unique graph name.

The return value of this method is the transposed PgxGraph instance.

Note: The Mode.MUTATE_IN_PLACE option is only applicable if the graph is marked as mutable. Every graph is immutable by default when loaded into PGX. (PGX may share the graph instance between multiple clients as discussed here). To make a PgxGraph mutable, the client should create a private copy of the graph first, using one of the following methods:

PgxFuture<PgxGraph> cloneAsync()
PgxFuture<PgxGraph> cloneAsync(String newGraphName)
PgxFuture<PgxGraph> cloneAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, String newGraphName)

or their blocking variants:

PgxGraph clone()
PgxGraph clone(String newGraphName)
PgxGraph clone(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, String newGraphName)

As with transpose(), the user can specify optional properties of the graph to copy with vertexProps and edgeProps. If no properties are specified, all of the original graph's properties will be copied into the new graph instance. The user can specify the name of the newly created graph instance with newGraphName.

Undirecting Graphs

The following methods create the undirected version of a graph instance:

PgxFuture<PgxGraph> undirectAsync()
PgxFuture<PgxGraph> undirectAsync(String newGraphName)
PgxFuture<PgxGraph> undirectAsync(MultiEdges multiEdges, SelfEdges selfEdges, Mode mode, String newGraphName)
PgxFuture<PgxGraph> undirectAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, MultiEdges multiEdges, SelfEdges selfEdges, Mode mode, String newGraphName)

As with simplify, PGX provides blocking convenience versions for those operations:

PgxGraph undirect()
PgxGraph undirect(String newGraphName)
PgxGraph undirect(MultiEdges multiEdges, SelfEdges selfEdges, TrivialVertices trivialVertices, Mode mode, String newGraphName)
PgxGraph undirect(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, MultiEdges multiEdges, SelfEdges selfEdges, Mode mode, String newGraphName)

The first two methods create an undirected version of the graph while copying all of the vertex properties. newGraphName is an optional argument to specify the name of the newly created graph instance.

In contrast, the third and fourth methods concurrently perform undirecting and simplifying of a graph. For the meaning of each parameter, refer to the steps for simplifying a graph in the above section.

All methods return an object of the undirected PgxGraph type.

Note, that an undirected graph has some restrictions. Some algorithms are only supported on directed graphs or are not yet supported for undirected graphs. Further, PGX does not support to store undirected graphs nor reading from undirected formats. Since the edges do not have a direction anymore, the behavior of pgxEdge.getSource() or pgxEdge.getDestination() can be ambiguous. In order to provide deterministic results, PGX will always return the vertex with the smaller internal id as source and the other as destination vertex.

Advanced Multi-Edge Handling

Both simplify() and undirect() support the removal of multi-edges using MultiEdges.REMOVE_MULTI_EDGES. If this parameter is set, all multi-edges in this graph are removed, i.e., collapsed. Whenever several multi-edges with edge properties are collapsed into one edge, one has to decide how to treat the corresponding properties. PGX supports two general strategies for this: picking and merging. If one chooses picking, PGX picks one edge out of every set of multi-edges and copies all its properties including the edge label and key into the new graph. In the case of merging, PGX creates a completely new edge out for every set of multi-edges. PGX determines the properties of these new edges by applying a MergingFunction on every property of the multi-edges.

If there are no multi-edges between two vertices, i.e., zero or only one edge, the chosen strategy does not has an effect on the outcome. The edge is kept with all its properties as it is.

Picking

This strategy can be used to pick an edge out of multi-edges. PGX allows the user to define several picking criteria. One can pick by:

  1. Property
  2. Label
  3. Edge-ID

Every picking criteria has to be combined with a PickingStrategyFunction. PGX supports either PickingStrategyFunction.MIN and PickingStrategyFunction.MAX, which picks the edge whose property/label/id is either minimal or maximal. If one does not specify a picking criteria, PGX will non-deterministically pick an edge out of the multi-edges.

A PickingStrategy can be created using a PickingStrategyBuilder, which can be retrieved by calling createPickingStrategyBuilder() on the target graph.

One can choose the decided picking criteria by calling one of the following functions:

PickingStrategyBuilder setPickByEdgeId(PickingStrategyFunction pickingStrategyFunction)
PickingStrategyBuilder setPickByLabel(PickingStrategyFunction pickingStrategyFunction)
PickingStrategyBuilder setPickByProperty(EdgeProperty edgeProperty, PickingStrategyFunction pickingStrategyFunction)
PickingStrategyBuilder setPickByProperty(String propertyName, PickingStrategyFunction pickingStrategyFunction)

The following figure shows how PGX picks the edge with the minimal cost and takes all its properties.

Simplifying graph using a picking strategy

Figure: Simplifying a graph using a picking strategy

Merging

This strategy can be used to merge the properties of multi-edges. PGX allows the user to define a MergingFunction for every property. Currently, PGX supports: - MergingFunction.MIN - MergingFunction.MAX - MergingFunction.SUM Note, that SUM is only defined on numeric properties.

Simplifying graph using a merging strategy

Figure: Simplifying a graph using a merging strategy

The following figure shows how PGX merges the different edge properties and labels. PGX takes the minimal cost, the sum of distances and the maximal edge label.

StrategyBuilder in General

Both StrategyBuilders allow the same configurations as already known from simplify and undirect. By default, they use the same values as in the convenience methods of simplify() and undirect(). This includes that all properties are kept by default. If one wants to drop specific properties, one can either use the dropVertexProperty() or dropEdgeProperty() functions.

MutationStrategyBuilder setNewGraphName(String newGraphName)
MutationStrategyBuilder setCopyMode(Mode mode)
MutationStrategyBuilder setTrivialVertices(TrivialVertices trivialVertices)
MutationStrategyBuilder setSelfEdges(SelfEdges selfEdges)
MutationStrategyBuilder setMultiEdges(MultiEdges multiEdges)
MutationStrategyBuilder dropVertexProperties(Collection<VertexProperty<?, ?>> vertexProperty)
MutationStrategyBuilder dropEdgeProperties(Collection<EdgeProperty<?>> edgeProperty)
MutationStrategyBuilder dropVertexProperty(VertexProperty<?, ?> vertexProperty)
MutationStrategyBuilder dropEdgeProperty(EdgeProperty<?> edgeProperty)
MutationStrategy build()

Simplify() and undirect() can be called using a MutationStrategy as follows:

MutationStrategy strategy = strategyBuilder.build()
PgxGraph simplifiedGraph graph.simplify(strategy)
//OR
PgxGraph undirectedGraph graph.undirect(strategy)

Creating Subgraphs

PGX provides the following methods for creating subgraphs via a filter expression:

PgxFuture<PgxGraph> filterAsync(GraphFilter graphFilter)
PgxFuture<PgxGraph> filterAsync(GraphFilter graphFilter, String newGraphName)
PgxFuture<PgxGraph> filterAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, GraphFilter graphFilter, String newGraphName)

and the following blocking convenience methods:

PgxGraph filter(GraphFilter graphFilter)
PgxGraph filter(GraphFilter graphFilter, String newGraphName)
PgxGraph filter(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, GraphFilter graphFilter, String newGraphName)

As in the other graph mutating methods, the user has the option to specify the name of the subgraph with the newGraphName parameter and of choosing the vertex/edge properties to be copied into the subgraph (vertexProps and edgeProps). All of the above methods return a PgxGraph object which represents the created subgraph.

All filter methods require a GraphFilter argument containing a PGX filter expression. Fundamentally, the filter expression is a Boolean expression that is evaluated for every vertex/edge in the original graph (in parallel). If the expression is evaluated as true for the vertex/edge, then the vertex/edge is included in the subgraph.

Refer to this document for more details about the filter expressions.

Creating a Bipartite Subgraph

PGX enables the client to create a bipartite subgraph with the following methods:

PgxFuture<BipartiteGraph> bipartiteSubGraphFromLeftSetAsync(VertexSet<?> vertexSet)
PgxFuture<BipartiteGraph> bipartiteSubGraphFromLeftSetAsync(VertexSet<?> vertexSet, String newGraphName)
PgxFuture<BipartiteGraph> bipartiteSubGraphFromLeftSetAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, VertexSet<?> vertexSet, String newGraphName)
PgxFuture<BipartiteGraph> bipartiteSubGraphFromLeftSetAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, VertexSet<?> vertexSet, String newGraphName, String isLeftPropName)

or their blocking counter-parts:

BipartiteGraph bipartiteSubGraphFromLeftSet(VertexSet<?> vertexSet)
BipartiteGraph bipartiteSubGraphFromLeftSet(VertexSet<?> vertexSet, String newGraphName)
BipartiteGraph bipartiteSubGraphFromLeftSet(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, VertexSet<?> vertexSet, String newGraphName)
BipartiteGraph bipartiteSubGraphFromLeftSet(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, VertexSet<?> vertexSet, String newGraphName, String isLeftPropName)

Noticeably, the methods require an additional argument vertexSet, which points to a set of vertices whose elements (vertices) would contain the left vertices (i.e. vertices on the left side of the bipartite graph that have only edges to vertices on the right side) in the resulting bipartite graph.

Note: When creating the bipartite subgraph, PGX automatically inserts an additional boolean vertex property isLeft. The value of this property is set true for the left vertices and false for the right vertices in the bipartite subgraph. The name of the isLeft vertex property can be obtained with getIsLeftPropertyAsync() (or its blocking version getIsLeftProperty()) on the returned BipartiteGraph object.

The user has the option to specify a name for the newly created graph (newGraphName) as well as a custom name for the Boolean left-vertex indicating property (isLeftPropName). The user can also specify the vertex/edge properties to be copied into the newly created graph instance (vertexProps and edgeProps).

All of above methods return the created BipartiteGraph instance.

Creating a Sparsified Subgraph

PGX supports creating a sparsified subgraph of a graph:

PgxFuture<PgxGraph> sparsifyAsync(double e)
PgxFuture<PgxGraph> sparsifyAsync(double e, String newGraphName)
PgxFuture<PgxGraph> sparsifyAsync(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, double e, String newGraphName)

Alternatively the following blocking counter-parts can be used:

PgxGraph sparsify(double e)
PgxGraph sparsify(double e, String newGraphName)
PgxGraph sparsify(Collection<VertexProperty<?, ?>> vertexProps, Collection<EdgeProperty<?>> edgeProps, double e, String newGraphName)

The double argument e is the sparsification coefficient with a value between 0.0 and 1.0.

The user again has the option to specify the name for the newly created graph (newGraphName) as well as the vertex/edge properties to be copied into the newly created graph instance (vertexProps and edgeProps).

The returned PgxGraph object represents a sparsified subgraph which has fewer edges than the original graph.

Mutating Graphs Through PGQL (Beta Feature)

Graphs can be mutated using the executePgql() and cloneAndExecutePgql() beta API methods and their non-blocking versions.

A graph can be mutated in place using the executePgql() API method. Insertion and deletion queries can only mutate transient graphs in place, whereas update queries can mutate non session-local graphs if they only update transient properties.

For example a new vertex can be inserted to a graph g using executePgql() the following way:

g.executePgql("MODFIY/*beta*/ (INSERT VERTEX v LABELS ('Male') PROPERTIES ( v.name = 'John' ) )")

A transient copy of the graph can be created using the different overloads of the cloneAsnyc method and their blocking versions.

In order to create a transient copy of the graph and execute the query against the new graph, the cloneAndExecutePgql() beta API method and its non-blocking version is defined.

Below you can find an example that creates an updated copy of the graph g using the cloneAndExecutePgql() API method. The returned graph will have the exact same edges and vertices as g excluding the vertex with id 11 and all of its edges.

modified_g = g.cloneAndExecutePgql("DELETE v FROM MATCH (v) WHERE id(v) = 11")

You can find more details on the API methods for executing MODIFY queries here.

For more details on modifying graphs through PGQL please refer to the corresponding section of the PGQL specification.