Loading SQL Property Graphs with Composite Keys
You can load a full SQL property graph or a sub-graph with composite keys into the graph server (PGX) memory using server-generated IDs.
Consider the following SQL property graph which is defined with composite vertex (FIRST_NAME, LAST_NAME) and edge (USER1_FIRST_NAME, USER1_LAST_NAME, USER2_FIRST_NAME, USER2_LAST_NAME) keys:
CREATE PROPERTY GRAPH SOCIAL_NETWORK
VERTEX TABLES (
USERS
KEY (FIRST_NAME, LAST_NAME)
PROPERTIES (FULL_NAME, USERNAME)
)
EDGE TABLES (
FRIENDS_WITH
KEY (USER1_FIRST_NAME, USER1_LAST_NAME, USER2_FIRST_NAME, USER2_LAST_NAME)
SOURCE KEY (USER1_FIRST_NAME, USER1_LAST_NAME) REFERENCES USERS (FIRST_NAME, LAST_NAME)
DESTINATION KEY (USER2_FIRST_NAME, USER2_LAST_NAME) REFERENCES USERS (FIRST_NAME, LAST_NAME)
NO PROPERTIES
) OPTIONS (ENFORCED MODE);
-
Load the complete graph into the graph server (PGX) memory using the
readGraphByNameAPI as shown:opg4j> var graph = session.readGraphByName("SOCIAL_NETWORK", GraphSource.PG_SQL) graph ==> PgxGraph[name=SOCIAL_NETWORK,N=3,E=3,created=1742566083153]PgxGraph graph = session.readGraphByName("SOCIAL_NETWORK", GraphSource.PG_SQL);>>> graph = session.read_graph_by_name("SOCIAL_NETWORK", "pg_sql") >>> graph PgxGraph(name: SOCIAL_NETWORK, v: 3, e: 3, directed: True, memory(Mb): 0)Also, it is important to note the following when creating graphs using composite keys:
-
It is recommended that you enable
ENFORCED MODEwhen creating the graph. This is to ensure the uniqueness for the specified composite keys, and avoid having the same vertex or edge being loaded multiple times with duplicate keys. -
As these IDs are automatically generated, there is no key mapping between the graph entities and the database elements. Therefore, these graphs are not synchronizable.
-
The data dictionary views which store the metadata related to the key columns of the SQL property graph gets updated on the composite keys as shown:
SQL> SELECT ELEMENT_NAME, COLUMN_NAME from ALL_PG_KEYS WHERE GRAPH_NAME = 'SOCIAL_NETWORK'; +------------------------------+ ELEMENT_NAME | COLUMN_NAME +------------------------------+ USERS | FIRST_NAME USERS | LAST_NAME FRIENDS_WITH | USER1_FIRST_NAME FRIENDS_WITH | USER1_LAST_NAME FRIENDS_WITH | USER2_FIRST_NAME FRIENDS_WITH | USER2_LAST_NAME 6 rows selected.
-
-
Optionally, query the graph in the graph server (PGX) to view the auto-generated vertex and edge keys.
opg4j> var pgql = ...> "SELECT * "+ ...> "FROM GRAPH_TABLE ( social_network "+ ...> "MATCH (a IS users) -[e IS friends_with]-> (b IS users) "+ ...> "COLUMNS (vertex_id(a), a.full_name, edge_id(e), b.full_name AS friend) "+ ...> ")" pgql ==> "SELECT * FROM GRAPH_TABLE ( social_network MATCH (a IS users) -[e IS friends_with]-> (b IS users) COLUMNS (vertex_id(a), a.full_name, edge_id(e), b.full_name AS friend) )" opg4j> g.queryPgql(pgql).print() +------------------------------------------------------------+ | vertex_id(a) | full_name | edge_id(e) | friend | +------------------------------------------------------------+ | USERS(0) | Steven King | FRIENDS_WITH(0) | Tom Rogers | | USERS(1) | Tom Rogers | FRIENDS_WITH(1) | Peter Hall | | USERS(2) | Peter Hall | FRIENDS_WITH(2) | Steven King | +------------------------------------------------------------+ $27 ==> PgqlResultSetImpl[graph=SOCIAL_NETWORK,numResults=3]String pgql = "SELECT * "+ "FROM GRAPH_TABLE ( social_network "+ "MATCH (a IS users) -[e IS friends_with]-> (b IS users) "+ "COLUMNS (vertex_id(a), a.full_name, edge_id(e), b.full_name) "+ ")"; PgqlResultSet rs = g.queryPgql(pgql); rs.print();>>> pgql = """ ... SELECT * ... FROM GRAPH_TABLE ( social_network ... MATCH (a IS users) -[e IS friends_with]-> (b IS users) ... COLUMNS (vertex_id(a), a.full_name, edge_id(e), b.full_name as name_of_friend) ... ) ... """ >>> graph.query_pgql(pgql).print() +---------------------------------------------------------------+ | vertex_id(a) | full_name | edge_id(e) | name_of_friend | +---------------------------------------------------------------+ | USERS(0) | Steven King | FRIENDS_WITH(0) | Tom Rogers | | USERS(1) | Tom Rogers | FRIENDS_WITH(1) | Peter Hall | | USERS(2) | Peter Hall | FRIENDS_WITH(2) | Steven King | +---------------------------------------------------------------+ -
Optionally, load and query only a subgraph of the
SOCIAL_NETWORKgraph which uses composite keys.opg4j> var subGraph = session.readSubgraph(). ...> fromPgSql("SOCIAL_NETWORK"). ...> queryPgql("MATCH (v1 IS users)-[e IS friends_with]->(v2 IS users) WHERE v1.full_name = 'Peter Hall'"). ...> load() graph ==> PgxGraph[name=SOCIAL_NETWORK_2,N=2,E=1,created=1743066245310] opg4j> subGraph.queryPgql("SELECT v1.full_name as name, v2.full_name as name_of_friend from MATCH (v1 IS users)-[e IS friends_with]->(v2 IS users)").print() +-----------------------------+ | name | name_of_friend | +-----------------------------+ | Peter Hall | Steven King | +-----------------------------+ $11 ==> PgqlResultSetImpl[graph=SOCIAL_NETWORK_3,numResults=1]PgxGraph subGraph = session.readSubgraph() .fromPgSql("SOCIAL_NETWORK") .queryPgql("MATCH (v1 IS users)-[e IS friends_with]->(v2 IS users) WHERE v1.full_name = 'Peter Hall'") .load(); PgqlResultSet rs = subGraph.queryPgql("SELECT v1.full_name as name, v2.full_name as name_of_friend from MATCH (v1 IS users)-[e IS friends_with]->(v2 IS users)"); rs.print();>>> sub_graph = session.read_subgraph_from_pg_sql("SOCIAL_NETWORK", ... "MATCH (v1 IS users)-[e IS friends_with]->(v2 IS users) WHERE v1.full_name = 'Peter Hall'", ... graph_name = "nw_sub_graph") >>> sub_graph.query_pgql("SELECT v1.full_name as name, v2.full_name as name_of_friend from MATCH (v1 IS users)-[e IS friends_with]->(v2 IS users)").print() +-----------------------------+ | name | name_of_friend | +-----------------------------+ | Peter Hall | Steven King | +-----------------------------+Also, note the following limitations when loading a subgraph from a graph that uses composite keys:
-
Loading a subgraph based on a condition that depends on the auto-generated key IDs is not supported. For instance:
MATCH (V) WHERE ID(V) = 'Person(0)' -
Subgraphs with auto-generated IDs cannot be expanded.
-