Knowledge graph QA, who founded the iPhone maker
Objective
Answering "Who founded the company that makes the iPhone?" requires linking three entities — product, company, person — across two hops. RAG with vector search alone struggles here because relevant facts are spread over multiple documents. A small knowledge graph answers it deterministically with one Cypher pattern, the foundation of any production KG-RAG system.
Step 1: Create the graph
// People
MERGE (steve_jobs:Person {name: "Steve Jobs", born: 1955})
MERGE (woz:Person {name: "Steve Wozniak", born: 1950})
MERGE (ronald:Person {name: "Ronald Wayne", born: 1934})
MERGE (gates:Person {name: "Bill Gates", born: 1955})
MERGE (allen:Person {name: "Paul Allen", born: 1953})
MERGE (musk:Person {name: "Elon Musk", born: 1971})
MERGE (tarpenning:Person {name: "Marc Tarpenning", born: 1964})
MERGE (eberhard:Person {name: "Martin Eberhard", born: 1960})
MERGE (bezos:Person {name: "Jeff Bezos", born: 1964})
MERGE (page:Person {name: "Larry Page", born: 1973})
MERGE (brin:Person {name: "Sergey Brin", born: 1973})
// Companies
MERGE (apple:Company {name: "Apple", founded: 1976, hq: "Cupertino"})
MERGE (msft:Company {name: "Microsoft", founded: 1975, hq: "Redmond"})
MERGE (tesla:Company {name: "Tesla", founded: 2003, hq: "Austin"})
MERGE (amazon:Company {name: "Amazon", founded: 1994, hq: "Seattle"})
MERGE (google:Company {name: "Google", founded: 1998, hq: "Mountain View"})
// Products
MERGE (iphone:Product {name: "iPhone", launched: 2007})
MERGE (mac:Product {name: "Mac", launched: 1984})
MERGE (windows:Product {name: "Windows", launched: 1985})
MERGE (modelS:Product {name: "Model S", launched: 2012})
MERGE (kindle:Product {name: "Kindle", launched: 2007})
MERGE (search:Product {name: "Google Search", launched: 1998})
// Founder edges
MERGE (steve_jobs)-[:FOUNDED]->(apple)
MERGE (woz)-[:FOUNDED]->(apple)
MERGE (ronald)-[:FOUNDED]->(apple)
MERGE (gates)-[:FOUNDED]->(msft)
MERGE (allen)-[:FOUNDED]->(msft)
MERGE (musk)-[:FOUNDED]->(tesla)
MERGE (tarpenning)-[:FOUNDED]->(tesla)
MERGE (eberhard)-[:FOUNDED]->(tesla)
MERGE (bezos)-[:FOUNDED]->(amazon)
MERGE (page)-[:FOUNDED]->(google)
MERGE (brin)-[:FOUNDED]->(google)
// Make edges
MERGE (apple)-[:MAKES]->(iphone)
MERGE (apple)-[:MAKES]->(mac)
MERGE (msft)-[:MAKES]->(windows)
MERGE (tesla)-[:MAKES]->(modelS)
MERGE (amazon)-[:MAKES]->(kindle)
MERGE (google)-[:MAKES]->(search);
Step 2: Answer the multi-hop question
// "Who founded the company that makes the iPhone?"
// Pattern: (Person)-[:FOUNDED]->(Company)-[:MAKES]->(Product {name: "iPhone"})
MATCH (founder:Person)-[:FOUNDED]->(company:Company)-[:MAKES]->(product:Product {name: "iPhone"})
RETURN founder.name AS founder,
founder.born AS born,
company.name AS company,
company.founded AS company_founded,
product.name AS product;
What's happening
- The two-hop pattern
(Person)-[:FOUNDED]->(Company)-[:MAKES]->(Product)reads exactly like the question — the structure of the query mirrors the sentence's clause structure. - All three founders of Apple are returned in one row each, with their birth year and Apple's founding year — context an LLM can use to compose a natural-language answer.
- This is the deterministic backbone of KG-RAG: graph patterns answer factual multi-hop questions precisely; vector search only handles fuzzy semantic recall. Combining them gives accuracy and recall without hallucination.
- Swap the product name to instantly answer "Who founded the company that makes the Kindle?" — the same pattern generalizes across the whole knowledge graph.
- In SQL this is a 3-way JOIN; in Cypher it is a structural query that scales to far more entity types and relationships without proportional schema/query churn.
Try this next
// "Which products were launched by companies founded after 1990?"
MATCH (founder:Person)-[:FOUNDED]->(c:Company)-[:MAKES]->(p:Product)
WHERE c.founded > 1990
RETURN c.name AS company, c.founded AS founded, collect(p.name) AS products;
// "Who are the people connected to the iPhone, however indirectly?"
MATCH (person:Person)-[:FOUNDED|MAKES*1..3]-(:Product {name: "iPhone"})
RETURN DISTINCT person.name;
// Company founder count
MATCH (p:Person)-[:FOUNDED]->(c:Company)
RETURN c.name AS company, count(p) AS founders, collect(p.name) AS founder_names
ORDER BY founders DESC;