10.4 Loading a Subgraph from a PGQL Property Graph
You can create a subgraph from a PGQL property graph and load it into memory in the graph server (PGX).
Instead of loading a full graph into memory, you can load a subgraph. This would consume less memory.
The following sections explain in detail on loading and expanding of subgraphs:
- PGQL Based Subgraph Loading
You can use thePgViewSubgraphReader#fromPgPgql
API to create an in-memory subgraph from a PGQL property graph using a set of PGQL queries. - Prepared PGQL Queries
You can also use prepared queries when loading a subgraph from a PGQL property graph. - Providing Database Connection Credentials
You can specify the database connection credentials with thePgViewSubgraphReader#fromPgPgql
API instead of using the default credentials of the current user. - Dynamically Expanding a Subgraph
You can expand an in-memory subgraph by loading another subgraph into memory and merging it with the current in-memory subgraph.
10.4.1 PGQL Based Subgraph Loading
You can use the PgViewSubgraphReader#fromPgPgql
API to
create an in-memory subgraph from a PGQL property graph using a set of PGQL queries.
These PGQL queries define the vertices and edges that are to be loaded into the subgraph. You can also use multiple PGQL queries and the resulting output graph is a union of the subgraphs, each being loaded independently by each PGQL query.
Note:
- Only non-composite vertex and edge keys are supported.
- Only numeric edge keys are supported.
- PGQL queries with
GROUP BY
orORDER BY
clauses are not supported for loading of subgraphs from a PGQL property graph.
The following example creates a subgraph from a PGQL property graph using multiple PGQL queries:
opg4j> var graph = session.readSubgraph().
...> fromPgPgql("FRIENDS").
...> queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'").
...> queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'").
...> load()
graph ==> PgxGraph[name=FRIENDS,N=3,E=1,created=1646726883194]
PgxGraph graph = session.readSubgraph()
.fromPgPgql("FRIENDS")
.queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'")
.queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
.load();
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS", ["MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'",
... "MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'"])
>>> graph
PgxGraph(name: FRIENDS, v: 3, e: 1, directed: True, memory(Mb): 0)
The following displays the output for the preceding PGQL query using the graph visualization tool.
Loading Subgraphs with Custom Names
By default, the new subgraph gets created with the same name as the PGQL property graph. Alternatively, if you want to load a subgraph with a custom name, then you can configure the subgraph name as shown:
opg4j> var graph = session.readSubgraph().
...> fromPgPgql("FRIENDS").
...> queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'").
...> queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'").
...> load("friends_network")
graph ==> PgxGraph[name=friends_network,N=3,E=1,created=1664458398090]
PgxGraph graph = session.readSubgraph()
.fromPgPgql("FRIENDS")
.queryPgql("MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'")
.queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
.load("friends_network");
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS",
... ["MATCH (v1:Person)-[e:FRIENDOF]->(v2:Person) WHERE id(v1) = 'PERSONS(1)'",
... "MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'"],
... graph_name="friends_network")
>>> graph
PgxGraph(name: friends_network, v: 3, e: 1, directed: True, memory(Mb): 0)
Loading a Subgraph by Explicitly Specifying the Schema Name
If you want to load a subgraph by reading a PGQL property graph from
another schema, you can additionally provide the schema name as an
argument to the PgViewSubgraphReader#fromPgPgql
API
. You must also ensure that you have READ
permission on all the underlying metadata and data tables for the
PGQL property graph.
For example:
opg4j> var graph = session.readSubgraph()
...> .fromPgPgql("GRAPHUSER", "FRIENDS")
...> .queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
...> .load()
graph ==> PgxGraph[name=FRIENDS,N=1,E=0,created=1672743755511]
PgxGraph graph = session.readSubgraph()
.fromPgPgql("GRAPHUSER", "FRIENDS")
.queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'")
.load();
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS",
... ["MATCH (v:Person) WHERE id(v) = 'PERSONS(2)'"],
... schema="GRAPHUSER")
Parent topic: Loading a Subgraph from a PGQL Property Graph
10.4.2 Prepared PGQL Queries
You can also use prepared queries when loading a subgraph from a PGQL property graph.
You can pass bind variables using prepared PGQL queries. The
PreparedPgViewPgqlQuery#preparedPgqlQuery
method adds a prepared
query to a list of queries that are executed to load the subgraph. The
PreparedPgViewPgqlQuery
API sets the bindings for the variables and
continues with the loading of the subgraph.
For example:
opg4j> var pgViewSubgraphReader = session.readSubgraph().
...> fromPgPgql("FRIENDS")
pgViewSubgraphReader ==> oracle.pgx.api.subgraph.PgViewSubgraphReader@33bfe6d3
opg4j> var preparedPgqlQuery = pgViewSubgraphReader.preparedPgqlQuery("MATCH (v1:Person)-[e:FriendOf]->(v2:Person) WHERE id(v2)=?")
preparedPgqlQuery ==> oracle.pgx.api.subgraph.PreparedPgViewPgqlQuery@2e6b379c
opg4j> preparedPgqlQuery = preparedPgqlQuery.withStringArg(1, "PERSONS(3)")
preparedPgqlQuery ==> oracle.pgx.api.subgraph.PreparedPgViewPgqlQuery@2e6b379c
opg4j> var graph = preparedPgqlQuery.load()
graph ==> PgxGraph[name=FRIENDS_2,N=3,E=2,created=1648566047855]
import oracle.pgx.api.subgraph.*;
…
…
PgViewSubgraphReader pgViewSubgraphReader= session.readSubgraph().fromPgPgql("FRIENDS");
PreparedPgViewPgqlQuery preparedPgqlQuery = pgViewSubgraphReader.preparedPgqlQuery("MATCH (v1:Person)-[e:FriendOf]->(v2:Person) WHERE id(v2)=?");
preparedPgqlQuery = preparedPgqlQuery.withStringArg(1, "PERSONS(3)");
PgxGraph graph = preparedPgqlQuery.load();
>>> from pypgx.api import PreparedPgqlQuery
>>> from pypgx.api import PreparedPgqlQueryStringArgument
>>> graph = session.read_subgraph_from_pg_pgql("FRIENDS",
... [PreparedPgqlQuery("MATCH (v1:Person)-[e:FriendOf]->(v2:Person) WHERE id(v2)=?", [PreparedPgqlQueryStringArgument("PERSONS(3)")])])
>>> graph
PgxGraph(name: FRIENDS, v: 3, e: 2, directed: True, memory(Mb): 0)
Parent topic: Loading a Subgraph from a PGQL Property Graph
10.4.3 Providing Database Connection Credentials
You can specify the database connection credentials with the
PgViewSubgraphReader#fromPgPgql
API instead of using the
default credentials of the current user.
The following example shows loading of a subgraph for non-default database connection settings:
opg4j> var graph = session.readSubgraph().
...> fromPgPgql("FRIENDS").
...> username("graphuser").
...> password("<password_for_graphuser>").
...> keystoreAlias("database1").
...> schema("GRAPHUSER").
...> jdbcUrl("jdbc:oracle:thin:@localhost:1521/orclpdb").
...> connections(12).
...> queryPgql("MATCH (a:Person)").
...> load()
graph ==> PgxGraph[name=FRIENDS,N=4,E=0,created=1648541234520]
PgxGraph graph = session.readSubgraph()
.fromPgPgql("FRIENDS")
.username("graphuser")
.password("<password_for_graphuser>")
.keystoreAlias("database1")
.schema("GRAPHUSER")
.jdbcUrl("jdbc:oracle:thin:@localhost:1521/orclpdb")
.connections(12)
.queryPgql("MATCH (a:Person)")
.load();
Parent topic: Loading a Subgraph from a PGQL Property Graph
10.4.4 Dynamically Expanding a Subgraph
You can expand an in-memory subgraph by loading another subgraph into memory and merging it with the current in-memory subgraph.
The PgxGraph.expandGraph()
method can be used to
expand a subgraph. The following applies when merging two graphs:
- Both the graphs can have separate sets of providers.
- A graph can have some providers same as the other graph. In this
case:
- The providers with the same names must have the same labels.
- The graph being merged must have the same or a common subset of properties as the base graph. However, it is possible that either of the graphs may have more number of properties.
The following example shows the expansion of the subgraph created in PGQL Based Subgraph Loading:
opg4j> graph = graph.expandGraph().
...> withPgql().
...> fromPgPgql("FRIENDS").
...> queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'").
...> queryPgql("MATCH (v:PERSON) WHERE id(v) = 'PERSONS(4)'").
...> expand()
graph ==> PgxGraph[name=anonymous_graph_152,N=4,E=3,created=1647347092964]
graph = graph.expandGraph()
.withPgql()
.fromPgPgql("FRIENDS")
.queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'")
.queryPgql("MATCH (v:PERSON) WHERE id(v) = 'PERSONS(4)'")
.expand();
>>> from pypgx.api import PreparedPgqlQuery
>>> from pypgx.api import PreparedPgqlQueryStringArgument
>>> graph = graph.expand_with_pgql(["MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'",
... "MATCH (v:Person) WHERE id(v)= 'PERSONS(4)'"])],
... pg_view_name="FRIENDS")
>>> graph
PgxGraph(name: anonymous_graph_66, v: 4, e: 3, directed: True, memory(Mb): 0)
The following displays the output for the preceding PGQL
query using the graph visualization tool. The subgraph is now
expanded to include the friendOf
relationship for
PERSONS(2)
in addition to
PERSONS(1)
which was already existing in
the subgraph.
Expanding a Subgraph by Explicitly Specifying the Schema Name
When expanding a graph, you can load another subgraph by
reading a PGQL property graph
from a different schema. For this, you must provide the schema name
as an argument to the
PgqlViewGraphExpander#fromPgPgql
API. You
must also ensure that you have READ
permission on
all the underlying metadata and data tables for the PGQL property graph.
For example:
opg4j> graph = graph.expandGraph().
...> withPgql().
...> fromPgPgql("GRAPHUSER", "FRIENDS").
...> queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(1)'").
...> expand()
graph ==> PgxGraph[name=anonymous_graph_18,N=1,E=0,created=1672848726308]
graph = graph.expandGraph()
.withPgql()
.fromPgPgql("GRAPHUSER", "FRIENDS")
.queryPgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(1)'")
.expand();
>>> graph = graph.expand_with_pgql("MATCH (v:Person) WHERE id(v) = 'PERSONS(1)'",
... pg_view_name="FRIENDS", schema="GRAPHUSER")
>>> graph
PgxGraph(name: anonymous_graph_6, v: 2, e: 0, directed: True, memory(Mb): 0)
Using Merging Strategy
When expanding a graph, some vertices and edges that are in the new graph data may have already been loaded in the base graph. In such cases, if the vertex and edge property values differ for all vertices and edges that are both in the base graph and in the new graph to be merged, then the following applies:
- If the merging strategy is
KEEP_CURRENT_VALUES
, then the vertex and edge property values coming from the new graph are ignored. - If the merging strategy is
UPDATE_WITH_NEW_VALUES
, then the vertex and edge property values are updated with the ones found in the new graph.
For example:
opg4j> import oracle.pgx.api.expansion.PropertyMergeStrategy
opg4j> graph = graph.expandGraph().
...> withPgql().
...> fromPgPgql("FRIENDS").
...> queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'").
...> preparedPgqlQuery("MATCH (v:PERSON) WHERE id(v) in ?").withStringArg(1, "PERSONS(4)").
...> vertexPropertiesMergingStrategy(PropertyMergeStrategy.UPDATE_WITH_NEW_VALUES).
...> expand()
import oracle.pgx.api.expansion.PropertyMergeStrategy;
graph = graph.expandGraph()
.withPgql()
.fromPgPgql("FRIENDS")
.queryPgql("MATCH (v1:PERSON) -[e:FRIENDOF]-> (v2:PERSON) WHERE id(v1) = 'PERSONS(2)'")
.preparedPgqlQuery("MATCH (v:PERSON) WHERE id(v) in ?").withStringArg(1, "PERSONS(4)")
.vertexPropertiesMergingStrategy(PropertyMergeStrategy.UPDATE_WITH_NEW_VALUES)
.expand();
Parent topic: Loading a Subgraph from a PGQL Property Graph