What a Knowledge Graph Is, Concretely
8 min read · updated August 4, 2026
A knowledge graph is a set of statements of the form subject, predicate, object, where the subjects and objects are identified things rather than strings. That is the whole definition. Everything else — ontologies, inference, query languages — is machinery built on top of it, and none of it is worth reading about until the base idea is concrete.
One sentence, twelve triples
Take a sentence of the sort that appears in a supplier database or a trade press article:
“Acme Robotics, founded in Dresden in 2011, supplies harmonic drives to Vandenberg Automation, whose chief technology officer is Ines Karlsson.”
A human reads that as one fact. A graph reads it as about a dozen, each of which can be asserted, sourced, dated and queried on its own:
acme rdf:type Company acme legalName "Acme Robotics GmbH" acme foundedIn dresden acme foundingYear 2011 dresden rdf:type City dresden locatedIn germany acme supplies vandenberg harmonicDrive rdf:type ProductCategory acme producesCategory harmonicDrive vandenberg rdf:type Company karlsson rdf:type Person karlsson holdsRole cto_vandenberg cto_vandenberg roleAt vandenberg cto_vandenberg roleTitle "Chief Technology Officer"
Two things in that list are worth noticing before anything else. The first is that acme, dresden and karlsson are identifiers, not words. They are not the strings “Acme Robotics” or “Dresden”; they are handles for the things those strings refer to, and the strings hang off them as properties. That single move is what makes a graph a graph rather than a pile of text.
The second is cto_vandenberg. The sentence said Karlsson is CTO of Vandenberg — a fact about three things at once, which does not fit in a two-ended edge. So the role itself becomes a node. That pattern has a dozen names (reification, an n-ary relation, a bridge node, an association class) and you will reach for it within an hour of starting any real model. It is also where you later attach the dates, which is the subject of temporal knowledge graphs.
The anatomy of a triple
| Part | Description |
|---|---|
| subject | Always an identifier for a thing. Never a literal value. |
| predicate | The relationship or attribute name. Comes from a fixed vocabulary you control — this is the part that must not be invented per-record. |
| object | Either another identifier (making an edge in the graph) or a literal value: a string, a number, a date. |
The distinction between an object that is an identifier and one that is a literal is the most consequential modelling decision you make repeatedly. acme foundedIn "Dresden" is a dead end: the string cannot have a population, a country, or a second name in another language. acme foundedIn dresden is a step you can walk across, which is what lets a query ask for suppliers founded in Germany without anybody having written the word Germany next to Acme.
The rule of thumb that survives contact with production: if you can imagine ever wanting to say something about the value, it is a node. Cities, product categories, currencies, job titles, regulatory classifications and units of measurement all end up as nodes. Free-text descriptions, timestamps and counts stay literals.
The same facts in a relational database
Nothing above requires a graph database. The same twelve statements fit a perfectly ordinary schema, and for a great many projects that is the right place to start:
CREATE TABLE company ( id text PRIMARY KEY, legal_name text NOT NULL, founded_in text REFERENCES city(id), founding_year int ); CREATE TABLE supplies ( supplier_id text REFERENCES company(id), buyer_id text REFERENCES company(id), category_id text REFERENCES product_category(id), PRIMARY KEY (supplier_id, buyer_id, category_id) ); CREATE TABLE role ( id text PRIMARY KEY, person_id text REFERENCES person(id), company_id text REFERENCES company(id), title text NOT NULL );
A knowledge graph and a normalised relational schema are describing the same world. The difference is not expressive power at the level of one fact. It is what happens when the questions get longer and when the schema has to change.
Where the two stop being equivalent
The divergence is easiest to see in one specific question: which companies depend on Acme, at any depth, through any chain of suppliers? Acme supplies Vandenberg, Vandenberg supplies three integrators, and one of those supplies a car maker. In a property graph that is one line:
MATCH (acme:Company {id: 'acme'})-[:SUPPLIES*1..8]->(downstream:Company)
RETURN DISTINCT downstream.legal_nameIn SQL it is a recursive common table expression — entirely doable, and worth knowing, but a different shape of thing:
WITH RECURSIVE chain AS ( SELECT buyer_id, 1 AS depth FROM supplies WHERE supplier_id = 'acme' UNION SELECT s.buyer_id, c.depth + 1 FROM supplies s JOIN chain c ON s.supplier_id = c.buyer_id WHERE c.depth < 8 ) SELECT DISTINCT buyer_id FROM chain;
Note UNION rather than UNION ALL: without deduplication a cycle in the supply chain — which absolutely exists in real procurement data — makes that query run until it is killed. Cycle safety is something the graph query gets from DISTINCT and the depth bound; in SQL it is yours to remember.
The second divergence is schema change. Adding “Acme also holds a certification issued by a body in Belgium” to the graph is three new triples and no migration. In the relational schema it is a new table, a foreign key, a deployment, and a conversation with whoever owns that database. Neither is wrong; they price flexibility differently, and a graph pays for that flexibility by giving up the guarantees a fixed schema hands you for free.
The three layers of a real graph
- Instances. The facts about particular things: Acme, Dresden, Karlsson. This is almost all of the volume.
- The schema or ontology. The classes and the permitted predicates: a
CompanymaysuppliesanotherCompany;foundingYeartakes an integer. This is what stops the graph acquiringsupplies,supplier_ofandsells_toas three unrelated predicates meaning one thing. See ontologies, taxonomies and schemas. - Provenance. Where each statement came from, when, and how confident anyone is. Skipped in every tutorial and required in every production system, for the plain reason that you will eventually need to retract everything that came from one bad source. See provenance in a knowledge base.
What it costs, honestly
The recurring cost of a knowledge graph is identity. Every fact you load has to be attached to the right node, which means deciding whether the “Acme Robotics GmbH” in your ERP is the “ACME Robotics” in the CRM. Get that wrong in one direction and the graph forks into duplicates; get it wrong in the other and two real companies are merged into one and the error propagates to every query. That problem is entity resolution, it is never finished, and it is the reason most abandoned graph projects were abandoned.
The second cost is that a graph gives you nothing until something queries it. A graph built because graphs are interesting, with no question waiting for it, becomes stale within a quarter. Start from the question — ideally one somebody is currently answering by hand across three systems — and model backwards from it. The page on questions vectors cannot answer is a catalogue of the question shapes that justify the work.
The smallest useful version
Nothing above requires a graph database, a triple store or an ontology editor. The smallest thing that is genuinely a knowledge graph is four tables in a database you already run, and it will answer real questions within a week:
entity(id, type, created_at) -- one row per real thing entity_alias(source, source_key, entity_id) -- every system's id for it attribute(entity_id, name, value, source_id) -- the literals edge(subject_id, predicate, object_id, source_id, valid_from, valid_to)
That schema carries identity, provenance and time, which are the three things a pile of spreadsheets does not have and the three that decide whether the thing survives its first year. Traversal is a recursive CTE rather than a path expression, which is more typing and the same answers. Move to a graph database when path queries dominate your workload or when the recursive CTEs stop being maintainable — not before, and not because the word graph appears in the requirements.
Populate it from the one place that already holds most of your relationships: foreign keys. A normalised relational schema is already an edge list wearing a different hat, and the initial load for many organisations is a mapping file, not an extraction pipeline. Reach for extraction from text for the facts that exist only in documents, which is a smaller share of them than most teams assume before they check.