Cypher Queries¶
PyGraphDB exposes a read-only Cypher subset through
GraphDB.query(cypher, parameters=None). It is designed around the features
PyGraphDB can execute efficiently today: indexed node scans, typed relationship
expansion, filtering, ordering, and chained MATCH clauses.
Relationship types come from edge.properties["type"]. Node labels are stored
on Node(labels=[...]).
Basic Result Shape¶
GraphDB.query returns a result with columns and records. Iterating the
result yields record dictionaries.
result = graph_db.query('MATCH (n:Drug) RETURN n.id, n.name LIMIT 10')
print(result.columns)
for record in result:
print(record["n.id"], record["n.name"])
Node Scans¶
Label scans use the label index. Inline properties are filtered and can use a registered property index.
graph_db.create_node_property_index("name")
graph_db.query('MATCH (n:Drug) RETURN n')
graph_db.query('MATCH (n:Drug {name: "Aspirin"}) RETURN n.id')
graph_db.query('MATCH (n:Drug:Approved) RETURN n.id')
graph_db.query('MATCH (n) RETURN n.id LIMIT 5')
Typed Relationship Traversal¶
Use an anchored pattern when you know the start node ID.
graph_db.query('MATCH (d {id: "drug-1"})-[:binds]->(p) RETURN p.id')
graph_db.query('MATCH (p {id: "protein-1"})<-[:binds]-(d) RETURN d.id')
graph_db.query('MATCH (n {id: "x"})-[:related]-(m) RETURN m.id')
Unanchored typed relationship scans are also supported.
graph_db.query('MATCH (a)-[r:binds]->(b) RETURN a.id, r.id, b.id')
graph_db.query('MATCH (a)-[r:binds|inhibits]->(b) RETURN r.id ORDER BY r.id')
Filtering¶
WHERE supports equality, inequality, ordered comparisons, AND, IN,
IS NULL, and IS NOT NULL for property references.
graph_db.query('MATCH (n:Drug) WHERE n.name = "Aspirin" RETURN n.id')
graph_db.query('MATCH (n:Person) WHERE n.age >= $age RETURN n.id', parameters={"age": 35})
graph_db.query('MATCH (n) WHERE n.kind IN ["drug", "protein"] RETURN n.id')
graph_db.query('MATCH (n) WHERE n.name IS NOT NULL RETURN n.id')
Relationship predicates work in anchored traversals and unanchored relationship scans. When an edge property index exists, exact and range predicates on typed relationship scans can use the composite type/property index.
graph_db.create_edge_property_index("score")
graph_db.query('MATCH (a)-[r:binds]->(b) WHERE r.score >= 0.8 RETURN r.id, b.id')
Projection and Result Shaping¶
Use aliases, RETURN *, DISTINCT, ORDER BY, SKIP, and LIMIT.
graph_db.query('MATCH (n:Drug) RETURN n.id AS id, n.name AS name ORDER BY name')
graph_db.query('MATCH (n) RETURN DISTINCT n.kind ORDER BY n.kind')
graph_db.query('MATCH (a)-[r:binds]->(b) RETURN * LIMIT 10')
Special projections prefer entity identity over user properties:
n.idandr.idreturn entity IDs.n.labelsreturns node labels.r.sourceandr.targetreturn relationship endpoints.Missing properties project as
None.
Chained MATCH Clauses¶
Multiple MATCH clauses execute as a row pipeline. Reusing a variable enforces
that it refers to the same entity.
graph_db.query(
'MATCH (d:Drug {name: "Aspirin"}) '
'MATCH (d)-[r:binds]->(p) '
'RETURN d.id, r.score, p.id'
)
Sampling Procedure¶
PyGraphDB also exposes typed path sampling through a project-specific procedure. This is not standard openCypher syntax.
result = graph_db.query(
'CALL pg.sample_typed_paths(["drug-1"], '
'[{"edge_type": "binds", "direction": "out", "sample_size": 2}]) '
'YIELD path RETURN path LIMIT 1'
)
Current Limitations¶
Unsupported syntax raises ValueError. The current Cypher API does not yet
support:
mutating queries such as
CREATE,SET,DELETE, orMERGEaggregation such as
countorcollectWITHOPTIONAL MATCHvariable-length paths
multiple pattern parts inside one
MATCHclausepath values such as
p = (a)-[:T]->(b)