Cypher QueriesΒΆ
PyGraphDB includes an initial read-only Cypher API through
GraphDB.query(cypher). The current implementation is intentionally small and
maps directly to features that already have efficient database APIs: indexed
label scans, anchored typed traversal, and typed path sampling.
Relationship types are read from edge.properties["type"]. Node labels are
stored natively through Node(labels=[...]) and maintained in a sorted label
index.
Supported Feature MatrixΒΆ
The table below distinguishes features available through the Python database API from features exposed through the Cypher API.
Legend: β supported, π‘ partially supported, β not supported.
Feature |
DB API |
Cypher API |
Notes |
|---|---|---|---|
Node and edge property storage |
β |
β |
Cypher can return bound |
Native node labels |
β |
β |
DB API supports |
Exact-match node property indexes |
β |
π‘ |
DB API supports explicit indexes via |
Exact-match edge property indexes |
β |
β |
DB API supports explicit indexes via |
Dedicated relationship type field |
π‘ |
π‘ |
Typed traversal uses |
Relationship type catalog |
β |
β |
DB API supports |
Anchored one-hop typed traversal |
β |
β |
DB API uses |
Anchored multi-hop typed traversal |
β |
β |
Cypher supports repeated outgoing typed hops from an anchored start node. |
Reverse typed traversal |
β |
β |
DB API supports |
Undirected typed traversal |
β |
β |
DB API supports |
Untyped BFS traversal |
β |
β |
Available as |
Single-hop typed neighbor sampling |
β |
β |
Available as |
Multi-hop typed path sampling |
β |
β |
Cypher exposes this through |
Materialized sampled subgraph |
β |
β |
Available as |
Property filtering with |
π‘ |
β |
DB API has exact-match index lookup helpers, but Cypher |
Result limiting |
β |
β |
Cypher supports |
Mutating Cypher queries |
β |
β |
Use |
Indexed Label ScansΒΆ
Create nodes with native labels, then query by label without scanning every node.
graph_db.put_node(Node(node_id="drug-1", labels=["Drug"], properties={"name": "Aspirin"}))
result = graph_db.query('MATCH (d:Drug) RETURN d')
for record in result:
print(record["d"].get_id)
Indexed Label and Property LookupΒΆ
Exact-match property indexes are explicit. Register an index before relying on it for performance-sensitive lookup.
graph_db.create_node_property_index("name")
result = graph_db.query('MATCH (d:Drug {name: "Aspirin"}) RETURN d')
for record in result:
print(record["d"].properties["name"])
If a property index is not registered, Cypher still restricts the search to the label index and then filters decoded nodes in Python.
Property Projections and LimitsΒΆ
Use dot notation in RETURN to project values from bound nodes and
relationships. Missing properties return None. The special fields id and
labels are available on nodes; id, source, and target are
available on relationships.
result = graph_db.query('MATCH (d:Drug) RETURN d.id, d.name LIMIT 10')
for record in result:
print(record["d.id"], record["d.name"])
Anchored One-Hop TraversalΒΆ
Use GraphDB.query for an anchored outgoing typed traversal. The start node
must be constrained by id.
result = graph_db.query(
'MATCH (d {id: "drug-1"})-[:drug-to-protein]->(p) RETURN d, p'
)
for record in result:
print(record["d"].get_id, record["p"].get_id)
The result object exposes columns and records:
print(result.columns) # ("d", "p")
print(len(result))
Relationship VariablesΒΆ
Relationship variables can be bound and returned.
result = graph_db.query(
'MATCH (d {id: "drug-1"})-[r:drug-to-disease]->(x) RETURN d, r, x'
)
for record in result:
print(record["r"].get_id, record["r"].properties)
Relationship properties can be projected directly.
result = graph_db.query(
'MATCH (d {id: "drug-1"})-[r:drug-to-disease]->(x) RETURN r.id, r.type LIMIT 1'
)
Anchored Multi-Hop TraversalΒΆ
Cypher supports repeated outgoing typed hops from the anchored start node.
result = graph_db.query(
'MATCH (d {id: "drug-1"})-[:drug-to-protein]->(p)-[:protein-to-disease]->(x) RETURN d, p, x'
)
for record in result:
print(record["d"].get_id, record["p"].get_id, record["x"].get_id)
Relationship variables can be used across multiple hops as well.
result = graph_db.query(
'MATCH (d {id: "drug-1"})-[r1:drug-to-protein]->(p)-[r2:protein-to-disease]->(x) RETURN r1, r2, x'
)
Reverse and Undirected TraversalΒΆ
Anchored typed traversals can follow outgoing, incoming, or either-direction relationships.
incoming = graph_db.query(
'MATCH (p {id: "protein-1"})<-[:drug-to-protein]-(d) RETURN p, d'
)
undirected = graph_db.query(
'MATCH (p {id: "protein-1"})-[:drug-to-protein]-(n) RETURN n'
)
Direction can vary by hop:
result = graph_db.query(
'MATCH (x {id: "disease-1"})<-[:protein-to-disease]-(p)<-[:drug-to-protein]-(d) RETURN x, p, d'
)
Sampling ProcedureΒΆ
Typed path sampling is exposed as a PyGraphDB-specific procedure call. This is
not standard openCypher syntax; it delegates to GraphDB.sample_typed_paths.
result = graph_db.query(
'CALL pg.sample_typed_paths(["drug-1"], '
'[{"edge_type": "drug-to-protein", "direction": "out", "sample_size": 2}, '
'{"edge_type": "protein-to-disease", "direction": "out", "sample_size": 1}]) '
'YIELD path RETURN path'
)
for record in result:
print(record["path"])
Current Cypher LimitationsΒΆ
Unsupported Cypher features raise ValueError with a message describing the
supported subset. The current Cypher API does not yet support:
Multiple labels in one node pattern, such as
(n:Drug:Approved).Unanchored all-node scans such as
MATCH (n) RETURN n.WHEREpredicates.ORDER BY, aggregation, joins across separate patterns, or mutation clauses.