Architecture at a Glance

A two-minute overview of how pg_ripple is built. The full architectural reference lives at Reference → Architecture; this page is the summary you can hand to an architect during evaluation.


Where pg_ripple sits

┌────────────────────────────────────────────────────────────────────┐
│                          Your application                           │
│                                                                     │
│   psql / asyncpg / JDBC          HTTP / SPARQL Protocol             │
└──────────────┬───────────────────────────┬─────────────────────────┘
               │ SQL                       │ HTTP
               ▼                           ▼
┌────────────────────────┐    ┌────────────────────────┐
│   PostgreSQL 18        │    │  pg_ripple_http        │
│                        │◄───┤  (companion service)   │
│  ┌──────────────────┐ │    │  Rust + Axum + deadpool│
│  │   pg_ripple       │ │    └────────┬───────────────┘
│  │   extension       │ │             │
│  │  (Rust + pgrx)    │ │             │ pg_ripple.sparql(...)
│  └──────────────────┘ │             │
└────────────────────────┘             │
            │                          │
            ▼                          │
┌────────────────────────────────────────┘
│  Storage layer (PostgreSQL tables, all integer-encoded)
│
│   _pg_ripple.dictionary        — IRI / blank / literal → BIGINT
│   _pg_ripple.vp_<predicate_id> — one VP table per predicate
│   _pg_ripple.vp_rare           — long-tail predicates
│   _pg_ripple.embeddings        — pgvector vectors, HNSW indexed
│   _pg_ripple.kge_embeddings    — graph-structural embeddings
│   _pg_ripple.audit_log         — every SPARQL UPDATE
│   …

Everything is plain PostgreSQL. There is no separate graph store, no separate vector store, no separate cache. A single pg_dump captures the whole thing.


The five subsystems

SubsystemWhat it ownsImplemented in
DictionaryEncoding every IRI / blank node / literal as a stable BIGINTsrc/dictionary/
StorageVP tables, HTAP delta + main split, the merge background workersrc/storage/
SPARQL engineSPARQL text → algebra → SQL → SPI execution → decodesrc/sparql/
Datalog engineRule parser, stratifier, SQL compiler, OWL RL/EL/QL profilessrc/datalog/
SHACL validatorShapes → DDL constraints + async validation pipelinesrc/shacl/

All five live inside the same PostgreSQL process and the same SQL transaction. This is the property that makes hybrid retrieval, atomic record-linkage, and audit-grade provenance possible.


Three architectural choices that shape everything

1. Vertical Partitioning (VP) — one table per predicate

Every unique predicate gets its own table. vp_<id>(s, o, g, i, source) — all integers. Star patterns (same subject, multiple predicates) collapse into one self-join over a single subject value. There is no triples(s, p, o, g) mega-table.

The result: SPARQL star-pattern queries match the speed of a hand-written SQL query against an analogously-shaped relational schema. Often faster, because every join is integer-equality.

2. Dictionary encoding — BIGINTs everywhere

Every triple, even at the parser boundary, is converted to a tuple of BIGINT IDs before it touches storage. Joins are integer equality. Filters are integer comparison. Decoding to text happens only at query output. The dictionary uses XXH3-128 for collision-free hashing and an LRU shared-memory cache for hot terms.

3. HTAP storage — delta + main + merge worker

Heavy ingest goes into per-predicate delta tables (regular B-tree heap). Read queries see (main EXCEPT tombstones) UNION ALL delta. A background worker merges delta into BRIN-indexed main asynchronously. Writers never block readers; readers never see partial loads.


What you do not see in the diagram

These are deliberately invisible to the user but have outsized impact:

  • Statement-ID timeline — every triple carries a globally-unique SID from a shared sequence. Powers point_in_time() queries.
  • Predicate catalog_pg_ripple.predicates(id, table_oid, triple_count). Cached in shared memory; survives extension reloads.
  • Plan cache — translated SPARQL → SQL plans are cached by query text hash, with invalidation on schema change.
  • Background workers — merge worker, embedding worker (when auto_embed = on), CDC publisher.

How it scales

AxisMechanism
More CPU on one machineParallel merge workers, parallel Datalog stratum evaluation, PostgreSQL parallel scans on VP tables
More disk on one machineBRIN indexes on vp_<id>_main, dictionary cache sized by GUC
Many small concurrent queriesPostgreSQL connection pool + pg_ripple_http deadpool pool
Read replicaspg_ripple.read_replica_dsn routes read queries automatically
Across many machinesCitus integration: VP tables become distributed tables; bound-subject SPARQL patterns are pruned to one shard

For deep coverage of each axis see Operations → Scaling and Operations → Citus integration.


Where to read more