Forward-deployed / Learning zone
Knowledge graphsa standalone module
Lesson 04

Storage & querying

TL;DR

Once the graph exists, it has to live somewhere queryable. There are three honest options. A property graph database (Neo4j and kin, queried in Cypher/GQL) is the pragmatic default for product features. An RDF triple store (queried in SPARQL) is the standards-based choice when interoperability, formal semantics, or cross-organization data exchange matter. A graph layer on the database you already run (recursive SQL, or graph extensions on Postgres/warehouse) is the right answer more often than vendors admit, especially below a few million entities and three hops. The technical dividing line is the traversal-vs-join question. Graph databases make "follow five hops from here" fast and writable. Relational stores make it slow and unreadable — but if your queries never go deep, that advantage never cashes. Avoid the product-leader mistake: this is the least important decision in the module. Teams agonize over databases while the pipeline and ontology — which actually determine success — go under-resourced. Pick boring, pick managed, move on.

🎯 For the product leader

Why it matters — This is where the vendor money is, so it's where the noise is. Every graph-database vendor will frame your project as a database choice. It isn't. But the choice still sets your latency floor, your ops burden, and a real lock-in cost, because query languages don't port cheaply.

What it changes in your decisions — You ask for the query shapes first: how many hops, how much fan-out, what latency budget, embedded in which user-facing feature. Ask this before anyone names a product. Query shapes decide the store; the store never decides the product.

Ask yourself — "What's the deepest traversal on our roadmap, at what latency, inside which feature — and did we benchmark the boring option on that exact query?"

Risk if ignored — Six months of bake-off theater for a workload Postgres handles. Or the inverse: a relationship-heavy feature built on SQL collapses at demo scale, taking the roadmap down with it.

The traversal-vs-join argument, honestly

The core claim for graph databases: relationships are stored as direct pointers, so following an edge costs the same whether the graph holds a thousand nodes or a billion (index-free adjacency). Each relational join, by contrast, re-finds partners via index lookups that compound as hops multiply. The claim is true — for deep, path-shaped queries. "All customers exposed to supplier X through any chain of parts" is painful in SQL at hop four and trivial in Cypher. But for one- and two-hop lookups, aggregations, and reporting, a tuned relational store is equal or better, with operational maturity graphs still can't match. There is also a readability dividend that shows up in team velocity:

Traversal vs. join

Says what it means, vs. implements what it means

The variable-depth query is the tell — it compounds into feature velocity when relationship questions are your daily bread.

"Which customers are exposed to Supplia through any component chain?"
Graph query
MATCH (s:Supplier {name:'Supplia'}) -[:SUPPLIES]->(:Component) -[:PART_OF*1..4]->(:Product) <-[:COVERS]-(:Contract) <-[:HOLDS]-(c:Customer) RETURN DISTINCT c
Variable-depth paths are native; new edge types need no migration.
SQL — recursive CTE
WITH RECURSIVE part_chain AS ( SELECT ... FROM components ... UNION ALL SELECT ... JOIN part_chain ... ) SELECT DISTINCT ... four more joins ...
Works — but depth is hand-rolled; every new relationship is a schema change.
The graph query states the question. The SQL implements it. For one- and two-hop lookups, a tuned relational store is equal or better.

The variable-depth *1..4 is the tell. The graph query states the question; the SQL implements it. When relationship questions are your product's daily bread, that gap compounds into feature velocity. When they're occasional, it's a curiosity.

The three families

Property graph RDF triple store Graph layer on existing DB
Mental model Nodes & edges with property bags — a whiteboard drawing, stored Everything a triple; global identifiers (IRIs); formal semantics Your tables, plus recursive queries or a graph extension
Query language Cypher; GQL (the 2024 ISO standard descended from it) SPARQL (W3C standard) SQL + recursive CTEs, or vendor graph SQL
Strengths Developer-friendly, fast traversals, rich algorithm libraries, biggest talent pool Interoperability, standard vocabularies, inference/reasoning built in, cross-org data exchange Zero new infrastructure, one backup/security/ops story, your team already knows it
Weaknesses Historically vendor-flavored (GQL is fixing this); semantics live in your docs, not the store Steeper learning curve, thinner tooling and talent, reification friction for edge properties Deep/variable-depth traversal slow and brittle; graph algorithms mostly absent
Natural home Product features: recommendations, fraud, 360° views, GraphRAG Regulated and cross-organization domains: pharma, government, publishing, finance reference data Modest scale, shallow hops, or proving value before buying infrastructure

Deployment nuance worth knowing exists — native stores vs. multi-model engines vs. graph-on-warehouse, managed offerings from every major cloud — but it's an engineering-owned decision. Your leverage comes earlier, in choosing the family, driven by query shapes and interoperability needs.

How to run the decision

  1. Write the query shapes down. Top ten roadmap queries: hops, fan-out, latency budget, freshness, and whether they sit inside a user-facing request path or a nightly batch. This one page does more than any bake-off.
  2. Benchmark the boring option first. Load a production-scale sample into what you already run. If it holds your latency at your depth, stop — revisit at the next order of magnitude. No graph database earns its ops burden below that bar.
  3. If traversal wins, default to a managed property graph. Largest talent pool, best algorithm support, and GQL standardization is steadily lowering the lock-in tax. Choose RDF deliberately, for interoperability or regulatory semantics — not by default.
  4. Contain the lock-in. Whatever the store: keep the ontology documented store-independently, keep the pipeline writing a neutral intermediate format, and keep raw sources replayable. Then the database is a component you can swap, not a decision you married. This is the same instinct as avoiding platform lock-in anywhere else.

One more boundary worth policing: graph stores serve knowledge; they don't replace your OLTP systems. The graph is a connective layer over systems of record — billing still lives in billing. Teams that try to make the graph the system of record inherit transaction-processing problems graph databases are bad at. They also lose the ability to rebuild the graph from sources when — not if — the pipeline needs a redo.

Failure modes

Practitioner checklist