Skip to content

SynapCores / Recipe

Drug interaction network for patient safety

Flag dangerous drug combinations across all patients via a prescribed-drug interaction graph

All recipes· graph· 7 minutesintermediatecypher
Instance: localhost:8080

Opens your running SynapCores (Drug interaction network for patient safety will be staged for a preview — nothing runs until you click Run). No instance yet? Install free in ~30s.

Share

Objective

Pharmacists and clinical decision-support systems must flag patients on combinations of drugs known to interact dangerously. Modeling Patient → Drug and Drug → Drug interactions as a graph turns the screening query into one MATCH that looks for triangles in the network — sub-second even across a hospital's entire prescription history.

Step 1: Create the graph

// Patients
MERGE (p1:Patient {mrn: "MRN-101", name: "Sarah Chen",   age: 67})
MERGE (p2:Patient {mrn: "MRN-102", name: "Raj Patel",    age: 54})
MERGE (p3:Patient {mrn: "MRN-103", name: "Mia Rossi",    age: 71})
MERGE (p4:Patient {mrn: "MRN-104", name: "Leo Park",     age: 49})
MERGE (p5:Patient {mrn: "MRN-105", name: "Eli Tanaka",   age: 62})

// Drugs
MERGE (warf:Drug {name: "Warfarin",   class: "Anticoagulant"})
MERGE (asp:Drug  {name: "Aspirin",    class: "NSAID"})
MERGE (clop:Drug {name: "Clopidogrel", class: "Antiplatelet"})
MERGE (sim:Drug  {name: "Simvastatin", class: "Statin"})
MERGE (ery:Drug  {name: "Erythromycin", class: "Antibiotic"})
MERGE (met:Drug  {name: "Metformin",  class: "Antidiabetic"})
MERGE (lis:Drug  {name: "Lisinopril", class: "ACE Inhibitor"})

// Prescriptions
MERGE (p1)-[:PRESCRIBED {since: "2026-01-12"}]->(warf)
MERGE (p1)-[:PRESCRIBED {since: "2026-03-04"}]->(asp)
MERGE (p2)-[:PRESCRIBED {since: "2025-11-22"}]->(sim)
MERGE (p2)-[:PRESCRIBED {since: "2026-04-15"}]->(ery)
MERGE (p3)-[:PRESCRIBED {since: "2026-02-08"}]->(warf)
MERGE (p3)-[:PRESCRIBED {since: "2026-02-08"}]->(clop)
MERGE (p4)-[:PRESCRIBED {since: "2025-06-10"}]->(met)
MERGE (p4)-[:PRESCRIBED {since: "2025-06-10"}]->(lis)
MERGE (p5)-[:PRESCRIBED {since: "2026-03-30"}]->(asp)
MERGE (p5)-[:PRESCRIBED {since: "2026-03-30"}]->(clop)

// Known interactions (severity 1=mild, 2=moderate, 3=severe)
MERGE (warf)-[:INTERACTS_WITH {severity: 3, effect: "Major bleeding risk"}]->(asp)
MERGE (warf)-[:INTERACTS_WITH {severity: 3, effect: "Major bleeding risk"}]->(clop)
MERGE (asp)-[:INTERACTS_WITH  {severity: 2, effect: "Increased bleeding"}]->(clop)
MERGE (sim)-[:INTERACTS_WITH  {severity: 3, effect: "Rhabdomyolysis risk"}]->(ery);

Step 2: Find at-risk patients across the entire panel

// Triangle: Patient -> drugA, Patient -> drugB, drugA <-> drugB interacts.
MATCH (p:Patient)-[:PRESCRIBED]->(a:Drug)-[ix:INTERACTS_WITH]-(b:Drug)<-[:PRESCRIBED]-(p)
WHERE id(a) < id(b)              // de-duplicate the unordered drug pair
RETURN p.mrn  AS mrn,
       p.name AS patient,
       a.name AS drug_a,
       b.name AS drug_b,
       ix.severity AS severity,
       ix.effect   AS effect
ORDER BY severity DESC, patient;

What's happening

  • The pattern matches a triangle: same patient, two drugs they take, one interaction edge between the drugs. Cypher unifies the patient on both sides of the pattern automatically.
  • id(a) < id(b) is a standard idiom to avoid returning each interaction twice.
  • The interaction edge is undirected (-[ix:INTERACTS_WITH]-) because pharmacological interactions are symmetric — a single relationship covers both directions.
  • In SQL this is a 4-way join (patient_drug × drug_interactions × patient_drug × drugs) plus a filter to ignore the same drug — the graph version is shorter and runs in linear time per prescribed drug, not quadratic in the prescription table.
  • Severity 3 alerts feed directly into prescribing UIs as "do not dispense without override".

Try this next

MATCH (p:Patient)-[:PRESCRIBED]->(d:Drug)
RETURN p.name AS patient, collect(d.name) AS regimen, count(d) AS poly_count
ORDER BY poly_count DESC;
MATCH (d1:Drug)-[ix:INTERACTS_WITH]-(d2:Drug)
WHERE id(d1) < id(d2)
RETURN d1.name, d2.name, ix.severity AS severity, ix.effect
ORDER BY severity DESC;
MATCH (p:Patient)-[:PRESCRIBED]->(:Drug)-[:INTERACTS_WITH]-(:Drug)<-[:PRESCRIBED]-(p)
RETURN p.mrn, p.name, count(*)/2 AS conflicting_pairs;

Tags

graphcypherhealthcareintermediate