Skip to main content
Intermediate7 min read5 of 5

Ontology and Schema Design for Knowledge Graphs

The schema — the ontology — is what separates a useful knowledge graph from a pile of connected records. How to design one that serves AI systems, not just human browsers.

Ontology and Schema Design for Knowledge Graphs

A knowledge graph without a schema is just a graph — nodes and edges with no shared meaning. The ontology is what makes it a knowledge graph: the formal definition of what entity types exist, what properties they carry, and what relationship types are valid between them.

Getting the schema right is the most consequential design decision in a knowledge graph project. A good schema compounds in value over time. A poor schema makes every downstream AI application harder to build and trust.


What an Ontology Is

An ontology is a formal specification of:

  • Entity types (classes): what kinds of things exist — Person, Company, Contract, Policy, Product
  • Properties: what attributes each entity type has — a Person has name, role, clearance_level
  • Relationship types: what connections are valid between entity types — a Person works_for a Company, a Contract governed_by a Policy
  • Constraints: cardinality, domain, range — works_for connects Person → Company, not Contract → Person
flowchart TD
  subgraph ONT["Ontology — the schema layer"]
    P["Class: Person\n[name, role, clearance_level]"]
    C["Class: Company\n[name, industry, regulatory_status]"]
    CT["Class: Contract\n[id, value, status, created_at]"]
    PL["Class: Policy\n[name, applies_to, required_action]"]

    P -- "works_for (1..1 Company)" --> C
    CT -- "involves (1..* Company)" --> C
    CT -- "governed_by (0..* Policy)" --> PL
    P -- "has_authority_over (0..* Contract)" --> CT
  end

The ontology is the contract between the knowledge graph and everything that uses it — AI agents, search systems, analytics tools, audit logs.


Two Schema Styles: RDF and Property Graph

There are two main paradigms for knowledge graph schemas, each with different trade-offs:

RDF / OWL

RDF (Resource Description Framework) models everything as triples: subject → predicate → object. OWL (Web Ontology Language) adds formal reasoning capabilities.

:Acme_Corp rdf:type :Company . :Acme_Corp :industry "regulated" . :Alice rdf:type :Person . :Alice :works_for :Acme_Corp . :Contract_4421 :involves :Acme_Corp . :Contract_4421 :governed_by :VendorCompliancePolicy .

Best for: linked data, semantic web integration, formal reasoning, cross-organization knowledge sharing.

Property Graph

A property graph allows nodes and edges to carry arbitrary key-value properties directly. More flexible for operational use cases.

flowchart LR
  A["(Person)\nname: Alice\nrole: procurement\nclearance: L2"] -- "works_for\nsince: 2023-01" --> B["(Company)\nname: Acme Corp\nindustry: regulated\nstatus: active"]
  B -- "involved_in\nvalue: $400k" --> C["(Contract)\nid: C-4421\nstatus: pending"]
  C -- "governed_by\nmandatory: true" --> D["(Policy)\nname: VendorCompliancePolicy"]

Best for: operational AI applications, agent memory, enterprise knowledge graphs, GraphRAG systems.

DimensionRDF / OWLProperty Graph
ReasoningFormal, automatedManual via queries
FlexibilityHigh (open world)High (arbitrary properties)
Query languageSPARQLCypher / Gremlin / GQL
PerformanceSlower for large traversalsFast for pattern matching
EcosystemSemantic web, academiaEnterprise databases, AI platforms

Designing Entity Types

The most important design decision is what counts as an entity vs what is a property.

Rule of thumb: if something has relationships of its own, it is an entity. If it is just a fact about something else, it is a property.

flowchart TD
  subgraph WRONG["❌ Address as property only"]
    P1["Person: Alice\naddress: '42 Main St, London'"]
    P2["Company: Acme Corp\naddress: '42 Main St, London'"]
    P1 -.->|no link — same address not discoverable| P2
  end

  subgraph RIGHT["✅ Address as entity"]
    P3["Person: Alice"] -- lives_at --> ADDR["Address: 42 Main St, London"]
    P4["Company: Acme Corp"] -- registered_at --> ADDR
    ADDR -.->|now queryable: who shares this address?| ADDR
  end

Address-as-entity makes fraud detection, compliance, and customer 360 queries trivially expressible. Address-as-property makes them impossible without full-text scan.


Relationship Types: The Most Important Design Decisions

Relationship types carry the semantics of the graph. Generic relationship names like related_to or connected_with destroy the value of the schema — they tell the AI and the query system nothing.

flowchart TD
  subgraph BAD["❌ Generic relationships"]
    A1[Person] -- related_to --> B1[Company]
    A1 -- related_to --> C1[Contract]
    B1 -- related_to --> C1
  end

  subgraph GOOD["✅ Typed relationships"]
    A2[Person] -- works_for --> B2[Company]
    A2 -- has_approval_authority_over --> C2[Contract]
    B2 -- is_vendor_on --> C2
    B2 -- subject_to --> D2[Policy]
  end

Each typed relationship answers a specific business question directly. has_approval_authority_over tells an AI agent exactly who can approve a contract. related_to tells it nothing.

[Definition] Relationship typing is the single biggest driver of knowledge graph quality for AI applications. A GraphRAG system traverses relationships by type to answer questions — if the types are vague, the traversal cannot be constrained and returns noise alongside signal.


Entity Resolution: One Entity, One Node

The most common and most damaging knowledge graph quality problem is duplicate entities — the same real-world entity represented as multiple nodes because it comes from different source systems with different IDs.

flowchart TD
  subgraph BEFORE["Before entity resolution"]
    CRM["CRM: Acme Corp\ncustomer_id: 4421"]
    ERP["ERP: ACME CORPORATION\naccount: C-99-4421"]
    SUPP["Support: Acme corp.\nref: cust_4421_en"]
    RISK["Risk: Acme Corp Ltd\nregistry: 0291847"]
  end

  subgraph AFTER["After entity resolution"]
    CANON["Canonical: Acme Corp\n[id: company_0291847]"]
    CANON --> CRM2[CRM record]
    CANON --> ERP2[ERP account]
    CANON --> SUPP2[Support history]
    CANON --> RISK2[Risk profile]
  end

Without entity resolution, a question like "show me all compliance issues for Acme Corp" returns results for only one source system. With resolution, it returns the full picture across all four.

Entity resolution strategies:

  • Deterministic: match on canonical identifiers (company registry number, ISIN, ISBN)
  • Rule-based: if name is similar AND postcode matches → same entity
  • ML-based: train a classifier on known matches across systems

Schema Evolution: Planning for Change

Knowledge graph schemas evolve as the business and the AI applications built on them evolve. Design for change from the start:

flowchart LR
  V1["Schema v1\nPerson, Company, Contract"] --> V2["Schema v2\n+ Policy, Regulation\n(additive — no breakage)"]
  V2 --> V3["Schema v3\nContract.value split\ninto Contract.base_value + Contract.total_value\n(careful migration required)"]

Additive changes (new entity types, new relationship types, new optional properties) are safe — existing queries still work.

Breaking changes (renaming types, changing relationship direction, splitting properties) require coordinated migration with all downstream consumers.

[Key Insight] Design your initial schema to be intentionally minimal. It is far easier to add entity types and relationships later than to rename or restructure them once AI applications depend on them. Start with the 5–8 entity types most central to your highest-value use case.


A Practical Schema Starter for Enterprise AI

For most enterprise AI applications, this 6-entity starter schema covers the majority of grounding and agent memory needs:

flowchart TD
  USER["User\n[id, name, role, permissions]"]
  ENTITY["BusinessEntity\n[id, name, type, status]"]
  DOC["Document\n[id, title, type, created_at]"]
  EVENT["Event\n[id, type, timestamp, severity]"]
  POLICY["Policy\n[id, name, applies_to, action_required]"]
  TASK["Task\n[id, description, status, assigned_to]"]

  USER -- has_authority_over --> TASK
  USER -- created --> DOC
  ENTITY -- subject_to --> POLICY
  ENTITY -- involved_in --> EVENT
  DOC -- governs --> ENTITY
  TASK -- references --> ENTITY
  EVENT -- triggers --> POLICY

This schema supports: agent memory (Tasks), business grounding (BusinessEntity + Policy), document retrieval (Document), compliance reasoning (Event + Policy), and permission checks (User) — all with typed relationships that GraphRAG can traverse meaningfully.