GraphRAG vs Neo4j: supply-chain impact analysis and part substitution

Answer "what breaks if a supplier fails, and what can we substitute?" in one Cypher query — graph traversal to the products at risk plus a semantic hop to viable alternative parts — and see what the same thing costs on a Neo4j + vector-DB stack.

All recipes· graph· 12 minutesintermediate✓ Certified v1.14.0-cecypher
Instance: localhost:8080

Opens your running SynapCores (GraphRAG vs Neo4j: supply-chain impact analysis and part substitution will be staged for a preview — nothing runs until you click Run). No instance yet? Install free in ~30s.

Share

GraphRAG vs Neo4j: supply-chain impact analysis and part substitution

This is a spoke of a 5-part GraphRAG cluster. It applies the hub's core pattern — semantic recall + graph structure + LLM ranking in one Cypher query — to supply-chain risk. For the architecture argument in depth, read the pillar: GraphRAG vs Neo4j.

Objective

When a supplier goes dark — a fire, a port closure, a bankruptcy — the buyer's first two questions are structural and semantic: "Which of my products lose a part?" (a graph traversal) and "Is there a drop-in substitute part I can source elsewhere?" (a similarity search over part specs). Neither question alone is enough. Knowing a product is at risk without an alternative is just bad news; finding a spec-similar part without knowing it comes from a different, still-alive supplier is useless.

GraphRAG answers both in one shot. The textbook way to build it is a four-system stack: Neo4j for the bill-of-materials graph, a vector database for the part-spec embeddings, an orchestration layer to join them, and an LLM API to judge whether an alternative is really a viable substitute. Four services, several network hops per query, and a sync job to keep the graph and the vectors from drifting apart.

SynapCores collapses that into one query on one engine: parts carry their own spec embedding, [:SIMILAR_TO > 0.8] is a semantic hop inside Cypher, and llm_score(prompt, node) grades substitution viability inline. This recipe builds a small bill-of-materials graph and answers "supplier SUP-9 just failed — what breaks, and what do I swap in?" with a single Cypher statement — then shows you exactly what the Neo4j stack version would take.

Step 1: Build the supply-chain graph

Suppliers SUPPLY parts, parts are USED_IN products. Each part carries a 5-dimensional demo embedding of its engineering spec so the recipe is fast and deterministic; in production you generate them with EMBED('part spec sheet text') (384-dim by default). Parts with similar specs share a vector direction (±0.02), so a part and its viable alternative land in the same cluster.

// Parts — each with a spec embedding. Same cluster = interchangeable specs.
// Cluster A (deep-groove ball bearings): P-A1 and its alternative P-A2
MERGE (pA1:ScPart {id: "P-A1", name: "6205-2RS deep-groove ball bearing",
                   spec: "25x52x15mm, sealed, 14kN dynamic load",
                   embedding: [0.80, 0.10, 0.05, -0.05, 0.20]})
MERGE (pA2:ScPart {id: "P-A2", name: "6205-ZZ deep-groove ball bearing",
                   spec: "25x52x15mm, shielded, 14kN dynamic load",
                   embedding: [0.82, 0.08, 0.06, -0.04, 0.21]})
// Cluster B (1200V IGBT power modules): P-B1 and its alternative P-B2
MERGE (pB1:ScPart {id: "P-B1", name: "FZ600R12 IGBT power module",
                   spec: "1200V, 600A, half-bridge",
                   embedding: [-0.30, 0.60, 0.20, 0.05, 0.10]})
MERGE (pB2:ScPart {id: "P-B2", name: "SKM600GB IGBT power module",
                   spec: "1200V, 600A, half-bridge",
                   embedding: [-0.29, 0.61, 0.18, 0.06, 0.11]})
// Cluster C (die-cast housing) — unrelated specs, on its own axis
MERGE (pC1:ScPart {id: "P-C1", name: "Die-cast aluminum drive housing",
                   spec: "ADC12 alloy, 3.2kg, IP67",
                   embedding: [0.05, -0.40, 0.65, 0.10, -0.17]})

// Suppliers (one of them is about to fail)
MERGE (s9:ScSupplier {id: "SUP-9", name: "Baotou Precision Components", region: "Baotou, CN"})
MERGE (s3:ScSupplier {id: "SUP-3", name: "Nordwerk Bearings GmbH",     region: "Schweinfurt, DE"})
MERGE (s7:ScSupplier {id: "SUP-7", name: "Fuji Power Devices K.K.",    region: "Matsumoto, JP"})
MERGE (s5:ScSupplier {id: "SUP-5", name: "Éclair Semikron S.A.",       region: "Nuremberg, DE"})
MERGE (s2:ScSupplier {id: "SUP-2", name: "Alcoa Castings Inc.",        region: "Knoxville, US"})

// Products the parts go into
MERGE (prod1:ScProduct {id: "PRD-1", name: "Meridian-3 EV drive unit"})
MERGE (prod2:ScProduct {id: "PRD-2", name: "Aster-7 traction inverter"})

// Who supplies what
MERGE (s9)-[:SUPPLIES]->(pA1)
MERGE (s3)-[:SUPPLIES]->(pA2)
MERGE (s7)-[:SUPPLIES]->(pB1)
MERGE (s5)-[:SUPPLIES]->(pB2)
MERGE (s2)-[:SUPPLIES]->(pC1)

// Where the parts are used
MERGE (pA1)-[:USED_IN]->(prod1)
MERGE (pC1)-[:USED_IN]->(prod1)
MERGE (pB1)-[:USED_IN]->(prod2)
MERGE (pA2)-[:USED_IN]->(prod2);

Step 2: The vector half — find spec-similar parts

[:SIMILAR_TO > 0.8] walks from a seed part to the parts whose spec embeddings are near it. This is the "vector database" part — except it's a Cypher edge, not a separate service.

// "The 6205-2RS bearing (P-A1) is going out of supply.
//  Which other parts have interchangeable specs?"
MATCH (seed:ScPart {id: "P-A1"})-[:SIMILAR_TO > 0.8]->(alt:ScPart)
RETURN alt.id AS id, alt.name AS name, alt.spec AS spec;

Expected: P-A2 (6205-ZZ bearing) — the other cluster-A part, same 25x52x15mm 14kN spec. The IGBT modules and the aluminum housing sit on different embedding axes, so they don't come back. The seed is excluded from its own SIMILAR_TO neighbor set, so you get alternatives, not the part you started from.

Step 3: GraphRAG — impact traversal + substitution + LLM viability, one query

Now the payoff. Start from the failing supplier, traverse the structural edges to the products that lose a part (impact), then for each affected part take a semantic hop to a spec-similar alternative supplied by a different supplier, and let llm_score rate how viable a drop-in substitute it is — all in a single statement.

// "SUP-9 just failed. What products break, and what can I swap in from someone else?"
MATCH (s:ScSupplier {id: "SUP-9"})-[:SUPPLIES]->(p:ScPart)-[:USED_IN]->(prod:ScProduct)
MATCH (p)-[:SIMILAR_TO > 0.8]->(alt:ScPart)<-[:SUPPLIES]-(alt_s:ScSupplier)
WHERE alt_s <> s
WITH prod, p, alt, alt_s,
     llm_score("Rate 0-1 how viable a drop-in substitute this alternative part is for the missing part, given interchangeable specs", alt) AS viability
RETURN prod.name AS at_risk_product,
       p.name AS missing_part,
       alt.name AS alternative,
       alt_s.name AS alt_supplier,
       alt_s.region AS alt_region,
       viability
ORDER BY viability DESC;

Expected: one row — the Meridian-3 EV drive unit is at risk because it loses the 6205-2RS bearing (P-A1) from failed SUP-9; the viable substitute is the 6205-ZZ bearing (P-A2) from Nordwerk Bearings GmbH in Schweinfurt, DE — a different supplier on a different continent — with a high LLM viability score (~0.9, same 25x52x15mm 14kN spec). Vector-only search could surface the similar bearing, but it could not tell you which product breaks or that the alternative comes from a still-alive supplier — both of those live in the graph.

What's happening

Three capabilities compose in one statement:

  1. Impact (structure): (:ScSupplier)-[:SUPPLIES]->(:ScPart)-[:USED_IN]->(:ScProduct) is a plain graph traversal — from the failing supplier to the products that lose a part. This is the part Neo4j does well on its own.
  2. Substitution (semantics): (p)-[:SIMILAR_TO > 0.8]->(alt) is a vector hop over the part-spec embeddings, finding parts that are engineering-interchangeable even if their part numbers share nothing.
  3. Sourcing + judgment: (alt)<-[:SUPPLIES]-(alt_s) WHERE alt_s <> s walks back into the graph to confirm the alternative comes from a different supplier, then llm_score grades drop-in viability inline.

The traversal and the similarity hop read the same rows in the same store, so there is no set-intersection glue and no vector-DB sync job.

What this takes on a Neo4j + vector-DB stack (for reference — not executed)

The same capability on the classic stack spans four systems. This block is a reference comparison, not runnable SynapCores code:

# 1) Neo4j holds the bill-of-materials graph (Cypher) — but Neo4j has no native
#    embedding hop, so SIMILAR_TO does not exist. It can do the impact traversal,
#    and it can list the parts a failed supplier feeds, but nothing more:
#    (Neo4j Cypher)
MATCH (s:Supplier {id:'SUP-9'})-[:SUPPLIES]->(p:Part)-[:USED_IN]->(prod:Product)
RETURN prod.name, p.id      # -> at-risk products + missing part ids

# 2) A separate vector DB (Pinecone/Weaviate/pgvector) holds the part-spec
#    embeddings. You query it out-of-band for each missing part:
neighbors = index.query(vector=embed(part_spec), top_k=10)   # -> [alt part ids]

# 3) Neither system knows the other's data, so application/orchestration code
#    (LangChain) has to join back into Neo4j to find WHO supplies each alternative
#    and drop any still coming from the failed supplier:
for alt_id in neighbors:
    alt_supplier = neo4j.run("MATCH (as)-[:SUPPLIES]->(:Part {id:$id}) RETURN as", id=alt_id)
    if alt_supplier.id == 'SUP-9': continue        # app-side filter

# 4) A separate LLM API call scores substitution viability for each survivor:
for alt in survivors: score = openai.rank(prompt, alt)   # N more network calls

# Then keep Neo4j and the vector DB in sync forever with a CDC/ETL job.

Four systems, several network round trips per question, and a synchronization job. In SynapCores it was one Cypher query against one store — the bill-of-materials edges and the part-spec vectors are the same data. That is the whole argument of GraphRAG vs Neo4j.

Step 4: One more — single-source risk across the catalog

// "Which parts are single-sourced but DO have a spec-similar alternative
//  from another supplier we could qualify as a backup?"
MATCH (p:ScPart)-[:SIMILAR_TO > 0.8]->(alt:ScPart)<-[:SUPPLIES]-(alt_s:ScSupplier)
MATCH (p)<-[:SUPPLIES]-(cur_s:ScSupplier)
WHERE alt_s <> cur_s
RETURN p.name AS part, cur_s.name AS current_supplier,
       alt.name AS backup_option, alt_s.name AS backup_supplier
ORDER BY part;

Cleanup (Optional)

MATCH (n:ScPart) DETACH DELETE n;
MATCH (n:ScSupplier) DETACH DELETE n;
MATCH (n:ScProduct) DETACH DELETE n;

Use it from your app or agent

  • In production: replace the demo vectors with EMBED('part spec sheet text') when you MERGE parts (384-dim), and add CREATE VECTOR INDEX for large catalogs. The Cypher queries above don't change.
  • REST/SDK: every query here is a POST /v1/graph/match with {"sql": "<cypher>"}, or client.graph.cypher(...) in the Python SDK — one call, one auth token. Wire it to a supplier-status feed and the impact query becomes a real-time alert.
  • Why one engine: the bill-of-materials edges and the part-spec embeddings are the same rows in the same store, so there is no vector-DB sync job and no app-side join back to suppliers. Add the LLM viability step with llm_score without leaving the query.

Key Concepts Learned

  • Supply-chain GraphRAG = impact traversal + spec-similarity + LLM judgment. Vector-only search finds similar parts but can't tell you what breaks or who still supplies the alternative — those are edges in a graph.
  • [:SIMILAR_TO > t] is an inline vector hop — spec-interchangeable parts surface as a Cypher edge, with a tunable threshold for precision/recall.
  • Walking back into the graph ((alt)<-[:SUPPLIES]-(alt_s) WHERE alt_s <> s) turns a bare similarity result into an actionable, differently-sourced substitute.
  • llm_score(prompt, node) grades substitution viability inside the query — no app-side LLM loop.
  • The Neo4j stack needs four systems and a sync job for the same result; here the graph and the vectors are one dataset.

Next in this cluster: Knowledge base (hub) · Fraud-ring detection · Customer-360 Q&A · Product recommendations · Pillar: GraphRAG vs Neo4j

Tags

graphraggraphcyphersimilar_tosupply-chainriskneo4j

Run this on your own machine

Install SynapCores Community Edition free, paste the SQL or Cypher above into the bundled web UI, and watch it run.

Download Free CE