01
relational-schema-analyzer  ·  Apache-2.0

Your database already knows what it means

Most of an ontology is sitting in your schema. You can extract it without a language model — and there are good reasons to.

declared overlaid inferred
02
The question

Someone hands you 200 tables and asks what the data means

Not what columns exist — the catalog answers that. They mean the other thing:

  • Which tables are real concepts, and which are plumbing?
  • When orders.customer_id points at customers.id, what is that relationship called?
  • Does one customer have many orders, or exactly one?

Every technique for making enterprise data useful to AI — knowledge graphs, retrieval over structured data, semantic layers, agents that query a warehouse — needs a model of meaning, not a model of storage.

03
The usual options

Both well-trodden routes are bad

Model it by hand

An architect and a domain expert, table by table. It works. It takes months, costs a fortune, and goes stale the moment someone ships a migration.

Ask a language model

Fluent, well-organised, and confidently includes relationships that do not exist.

The failure mode isn't that the model is wrong. It's that wrong and right look identical in the output — and telling them apart means doing the manual work you were trying to skip.

04
The overlooked third option

A schema is already full of declarations about meaning

Made deliberately, by a human — then ignored by most tools that read it.

DeclarationWhat it actually asserts
PRIMARY KEYIdentity — what makes a row that thing
FOREIGN KEYA relationship, including its direction
UNIQUE on an FKCardinality — the difference between 1:1 and 1:N
CHECK (x IN …)The permitted states of a concept
COMMENTDocumentation written for exactly this purpose
junction tableA many-to-many relationship — not an entity

None of this requires inference. It requires reading. Commit to reading it properly and much of the conceptual model falls out deterministically: same input, same output, every time.

05
What it produces

Three artifacts, and every concept traces home

Physical schema

A faithful record of the source: tables, typed columns, keys, constraints, indexes, comments, provenance.

Conceptual model

Classes, relationships with cardinality, properties, class hierarchies — what the data means.

Mapping

The back-reference. Every class and property points at the exact table, column or constraint it came from.

Exports are W3C standards, not a proprietary format: OWL for the ontology, R2RML for the mapping.

06
The pipeline

Read, derive, export

01Source9 connectors, one interface
02Physicalcatalog introspection
03Baselinedeterministic rules
04Conceptualclasses + relationships
05ExportOWL · R2RML · JSON

An optional language-model pass sits beside step 03, refining names and flagging judgment calls. It is never required, and it never invents structure.

07
Worked example · the worst case

Four CSV files — no keys, no constraints, no comments

$ relational-schema-analyzer analyze --source csv --url ./library

ENTITIES:  Authors · Books · Loans · Members

Books → Authors    1:N
Loans → Books      1:N
Loans → Members    1:N

That is the right answer, recovered from column names and type compatibility alone. But the answer is not the interesting part.

08
Calibration is the feature

It got the right answer and told you not to trust it

"confidence": 0.64,
"reviewRequired": true,
"detectedPatterns": ["inferred_foreign_keys"],
"assumptions": [
  "No foreign keys were declared; 3 relationship(s) were
   inferred from naming heuristics (review)."
]

Give the same schema to PostgreSQL with the foreign keys declared and the relationships come back unflagged at high confidence — because now the database is the witness.

A tool that produces an ontology should say which parts it read, which it guessed, and how sure it is about the guesses.

09
The core idea

Three ways to know something — never blended

declared

The source catalog asserts it. Highest trust, no inference.

overlaid

A human wrote it down, in version control, with a reason.

inferred

Derived from naming, types, and optional value sampling. Scored and flagged.

The interesting engineering in a tool like this is rarely the inference. It is the bookkeeping about how much you know — and resisting the urge to flatten three epistemic states into one confident-looking answer.

10
Where the third status came from

Some catalogs know nothing at all

Pointed at a large public news-event dataset on a cloud warehouse, the extraction produced completely disconnected classes. The dataset declares no primary keys and no foreign keys — public datasets rarely bother. Correct, and useless.

The fix was not to guess harder. It was to let a human supply what the catalog lacks:

{ "tables": {
    "events": { "primaryKey": ["GLOBALEVENTID"] },
    "eventmentions": { "foreignKeys": [{
        "columns": ["GLOBALEVENTID"],
        "references": { "table": "events", "columns": ["GLOBALEVENTID"] },
        "comment": "codebook: mentions reference their event" }] } } }
  • The catalog always wins. An overlay fills gaps; it never overrides the database.
  • Labelled, not laundered. Human-asserted keys stay marked as such, forever.
  • A typo fails loudly. Silent no-ops surface as an empty ontology three steps later.
11
The stance

Deterministic first. The model works on the residue.

This is not an argument that language models are useless here. They are genuinely good at the semantic leftovers: naming, noticing that cust_ref and customer_id are the same idea, spotting that a table is really an event log.

The argument is that they should work on the 10% that needs judgment, grounded by the 90% you derived from evidence — rather than hallucinating over the whole thing.

  • Same input, same output — reproducible and auditable
  • Regression-testable: you cannot write a test against a coin flip
  • No API key, no token cost, no network
  • Every claim traces to a constraint you can go and look at
12
Coverage

Nine sources, one interface

KindSources
databasesPostgreSQL · MySQL / MariaDB · SQL Server · DuckDB
warehousesSnowflake · Databricks  (BigQuery in progress)
catalogsdbt manifests · Open Semantic Interchange models
filesCSV

The analysis is identical regardless of dialect — only the introspection differs. Adding a source is a connector plus its tests, with no change to the core.

13
Output

Standards on the way out

:Books_Authors a owl:ObjectProperty, owl:FunctionalProperty ;
  rdfs:domain :Books ;
  rdfs:range  :Authors .
:Books_Authors phys:mappingStyle "FOREIGN_KEY" .
:Books_Authors phys:tableName   "books" .
:Books_Authors phys:fromColumns "author_id" .
:Books_Authors phys:toColumns   "id" .

Every concept carries annotations pointing back at its physical origin, so "where did this come from?" always has an answer.

The companion R2RML mapping feeds straight into an off-the-shelf engine such as Ontop or Morph-KGC, giving a queryable knowledge graph over the live database with no hand-written mapping — normally where weeks of this work go.

14
The hard part

A physical schema is a record of performance decisions

Every denormalisation a DBA made for good reasons is a distortion of the concepts:

  • A customers table with company_name, company_address — a hidden Company, folded in to avoid a join
  • A party table holding people and organisations, told apart by party_type — two classes in one coat
  • A tags column containing "12, 45, 89" — a many-to-many stuffed into a string
  • Five rows per product with effective_date / expiration_date — a thing mixed with its history
  • total_lifetime_value — not a property at all, but a calculation over relationships, frozen

Some of this is measurable. Some is a judgment call no algorithm can settle — and that residue is exactly where a language model earns its place.

15
Status

Where it is

  • Apache-2.0, on PyPI, v0.6.0
  • Nine sources; deterministic baseline; optional LLM refinement
  • OWL (Turtle / JSON-LD) and R2RML exports; CLI, Python API, and an MCP server
  • Several hundred tests — feasible precisely because the core is deterministic

Next: a BigQuery connector, denormalisation detection, and SHACL validation shapes.

Default ontology IRIs are configurable; the library targets no particular database. It is used alongside ArangoDB — a database that stores documents and graphs together — but emits standards any consumer can read.

16
In one line

Listen to the database before reaching for a tool that guesses.

Ontology extraction is mostly a reading problem. The parts that need judgment deserve to be marked as such — not quietly absorbed into an answer that looks as confident as the rest.

github.com/ArthurKeen/relational-schema-analyzer

01 / 16
↑ ↓ to navigate