Build a semantic model
A semantic model turns SQL tables and other source data into a reusable domain layer you can query, validate, and eventually use with reasoners. This overview gives you a high-level picture of semantic modeling in PyRel, and links to task guides that show you how to do it.
What a semantic model is
Section titled “What a semantic model is”A semantic model is a shared, reusable way to define what your data means in your domain. In PyRel, it is more than renaming tables and columns. It lets you model the things you care about and validate them with logic and checks you can run repeatedly.
In PyRel, you build a semantic model using the following building blocks:
- Concepts: The types of entities in your domain, like “Person”, “Company”, or “Product”.
- Properties: Single-valued attributes of entities, like a person’s name or age.
- Relationships: Links between entities, like “Person works at Company”.
- Definitions: The base facts and logic that express domain knowledge, like “Alice is a Customer” or “Customers who spent more than $100 in the last month are VIPs”.
- Requirements: Reusable checks that enforce data validation and business rules.
Why build a semantic model
Section titled “Why build a semantic model”Do any of these sound familiar?
- You keep rewriting the same joins, filters, and “business rules” across notebooks and scripts.
- Different people (or dashboards) answer the “same” question differently because the logic is not centralized.
- Your data sources change, and you want to update mappings and rules once instead of chasing every downstream query.
- You need guardrails that catch bad data and broken assumptions early, before they turn into silent errors.
Semantic modeling solves these problems by letting you encode your domain knowledge in a shared layer that sits on top of your data sources.
Once you encode a concept, relationship, or definition in the model, every query can rely on it. That makes results more consistent, makes refactors cheaper, and makes it easier to onboard new teammates.
How semantic models relate to SQL and source data
Section titled “How semantic models relate to SQL and source data”Think of a semantic model as a layer that sits on top of your source data. It maps raw data into domain concepts and relationships, and then lets you build derived logic and requirements on top of that. Queries from notebooks, scripts, and applications can then use the model as a single source of truth for what things mean and how they relate.
Here’s a quick picture of how PyRel fits together: where your data comes from, what the semantic model does, and what runs queries against it:
Once you map sources into the model, every client can query the same shared meaning.
What modeling with PyRel looks like
Section titled “What modeling with PyRel looks like”PyRel is a declarative Python DSL for building and querying semantic models. This means you describe what is true for your model, not how to compute it.
In other words you:
- Declare what’s important in your domain.
- Let PyRel use those declarations to compute query results.
Here is a simple PyRel model that declares a Person concept, defines some facts about people, and then queries those facts:
from relationalai.semantics import Integer, Model, String
# Create a new Model instance.m = Model("PeopleModel")
# Declare a Person concept with name and age properties.Person = m.Concept("Person")Person.name = m.Property(f"{Person} is named {String:name}")Person.age = m.Property(f"{Person} is {Integer:age} years old")
# Define some Person entities.# In real models, you would usually load this data from a SQL table.m.define(Person.new(name="Alice", age=10), Person.new(name="Bob", age=30))
# Declare an Adult concept as a subtype of Person.Adult = m.Concept("Adult", extends=[Person])
# Define Adults as people with age >= 18.m.define(Adult(Person)).where(Person.age >= 18)
# Select names and ages of Adults.q = m.select(Adult.name, Adult.age)
# Inspect the query results.q.inspect()If you know SQL, you can think of a model as a sort of on-demand view that you build with Python code instead of a SQL query:
- Concepts and relationships make up the schema of your domain, similar to tables and columns.
- Definitions are like layered views that build on top of that schema using logic, except that they may contain advanced reasoning that is unavailable in SQL.
- When you query the model, PyRel evaluates the definitions it needs to answer that query. Data flows from your source tables, through the schema and logic in the model, into a table of results.
Concretely, when you select(Adult.name, Adult.age):
- You’re asking for a table of adults, with a
nameandagecolumn. - PyRel evaluates the
Adultdefinition to figure out whichPersonentities count. - It pulls
Person.nameandPerson.agefor those people from your sources, and returns the matching rows.
All of this happens without you writing a single loop or hand-coding the filtering and join logic yourself.
What you can do after the model is built
Section titled “What you can do after the model is built”Once you have stable declarations, definitions, and requirements, your model becomes a reusable domain layer. You can query it from notebooks, scripts, and applications, and evolve it as your understanding and requirements change, without breaking downstream clients.
Make decisions with advanced reasoning
Section titled “Make decisions with advanced reasoning”When your schema and requirements stop changing frequently, you can apply advanced reasoning on top of the same modeled meaning. Different reasoning styles help with different kinds of decisions:
- Rules-based reasoning: Capture complex business logic an decision trees to answer questions like “Which customers are eligible for this promotion?” or “What steps in this workflow are most likely to fail?”
- Graph reasoning: Answer questions about relationships and connections in your data, like “Who are the top influencers in this network?” or “How can I segment my customers based on their interactions?”
Learn more in our rules-based reasoning guides.
Explore in notebooks
Section titled “Explore in notebooks”When your schema, derived logic, and requirements live in the model, exploration stays consistent across cells and across people. That means you spend less time re-implementing joins and rules, and more time refining what you want to ask.
Export from scripts and jobs
Section titled “Export from scripts and jobs”Scripts and scheduled jobs make model-backed queries repeatable.
Because the model centralizes business logic, your automation reuses the same definitions and requirements that notebooks and applications rely on.
That keeps CI, pipelines, and production exports consistent as the model evolves.
When you need a durable output, export results into a table by chaining Fragment.into and Fragment.exec.
Embed in applications
Section titled “Embed in applications”Applications benefit most when the model becomes the shared source of truth for product logic. Reuse the same model-backed queries (or the exported tables) so behavior stays aligned with your domain definitions across services, endpoints, and teams.