Nori-Rel connects to PostgreSQL, Snowflake, and Databricks. It needs Python
3.11, 3.12, or 3.13. Install
nori-rel 0.4.3 or later with the extra for your
database and the local extra, as each tab under Connect shows; see
Installation. Local mode runs Nori in your process and
downloads its weights from Hugging Face on first use. A GPU is faster but not
required. The outputs on this page come from the public
RelBench rel-f1 Formula 1
database.Build a database from files
Skip this section if your data is already in related tables with declared keys. If your data is a folder of CSV or Excel exports, thenori-rel-prepare-data
skill walks an AI agent through turning it into a PostgreSQL database Nori-Rel
can use. The agent profiles the files, designs tables with declared keys, and
leaves out columns that would leak the future, such as a customer’s lifetime
total. Before it creates anything, it shows you every table, column, and
relationship it plans and waits for your confirmation.
SKILL.md as its instructions.
Connect
Keep anything that identifies your account in environment variables. Nori-Rel reads them in your process and never sends them anywhere. Replace every value marked# yours with your own: the user, role, key path,
host, warehouse, database, and schema shown are examples. Register the time
column of each event table. Tables without one, such as drivers, are
entities.
- PostgreSQL
- Snowflake
- Databricks
time_columns and print every table’s columns with their database
types:
rel-f1 in PostgreSQL, this prints the following (three of the nine
tables shown):
time_columns, and connect again. Here that is date in races and
results. races.time is text, so it can’t be a time column. drivers.dob is
a timestamp but it’s a date of birth, so drivers stays an entity. Type names
follow your database.
See the graph
discover returns the tables, keys, and links Nori-Rel found. It reads the
primary and foreign keys your database declares. Snowflake and Databricks
record keys without enforcing them, and Nori-Rel checks them before it uses
them. If your tables declare no keys, pass primary_keys= and foreign_keys=
to connect.
This helper turns the result into a Mermaid diagram:
rel-f1 it draws nine tables:
results, qualifying, and standings each link a driver to a race, and
drivers has no time column because a driver is an entity rather than an
event.
Set up the prediction
This example predicts each driver’s average finishing position over the next 60 days. In PQL that is one line. Four dates and one column set up the rest:anchor_timeis the date you predict from. Features for the drivers you score read only rows dated up to it.anchor_timesare past dates Nori learns from. At each one, Nori-Rel builds every driver’s features from rows dated up to that date and a label from the 60 days after it, so each date adds one example per driver. Each must be earlier thananchor_time.observed_throughis how far your data is complete. A past date is used only if its whole 60-day window ends by the earlier ofanchor_timeandobserved_through, so a partly loaded month can’t produce wrong labels. The latest timestamp in the database can’t stand in for it, because a partly loaded period still has rows.entity_created_atnames the column in the entity table (heredrivers) that says when each entity came into existence. A driver is left out of every past date before it, and a driver with no value is left out entirely. Most databases have acreated_atcolumn for this;rel-f1has none, so the date of birth stands in.
feature_strategy= picks how Nori-Rel builds the features, and
on_event prints each stage as it happens. Pick a tab: each runs the same
request. The rest of this page uses the NoriDFS result.
- NoriDFS
- FastDFS
- AgenticSearch
max_context_rows=12_000 keeps every candidate in play;
the default of 5,000 fills from the most recent dates and would drop the oldest
ones. entity_created_at="dob" keeps each driver out of dates before their
birth.
The events show where the time goes. Reading the snapshot takes most of it,
and that depends on your warehouse; planning features and running Nori take a
few seconds. To run in the background, call client.start_predict(...) with
the same arguments, then read run.events() or stop it with run.cancel().
Save the pipeline
details.pipeline records how the prediction was made: the task, the features
NoriDFS planned, and the model settings. It holds no credentials, rows, or
model weights. Save it to predict again later without a new feature search:
See the features
details.features is the matrix Nori scored: a pandas DataFrame with one row
per driver, indexed by entity_id, and one column per feature. Each column
name says what it reads: results.grid.mean is the mean of results.grid over
the driver’s results rows, and qualifying.constructors.count counts the
constructors reached through the driver’s qualifying rows. Transposed, each
row is a feature and each column a driver:
Replay the pipeline
Load the saved pipeline, in this process or another one, and predict with it. It reads the database again and rebuilds the same features with the saved plan, with no feature search:as_of to predict a new date with the same recipe. Each
replay reads fresh rows from the database.
Evaluate the predictions
To check the pipeline, backtest it: replay it from past dates whose next 60 days are already in the database, then compare with what happened. This loop replays the savedpipeline at eight dates, two months apart, starting in July
2003. Each replay builds its context and features only from rows dated before
its as_of, with the same features and settings every time. For a baseline,
it uses each driver’s average finish over the year before the date, a simple
“recent form” guess.
The actual values come from a query on the same database. connection is any
DB-API connection to it, such as psycopg.connect(...) or
snowflake.connector.connect(...). Quote column names the way your database
does.
feature_strategy="noridfs", because NoriDFS plans the same features at each
of these dates. A pipeline that holds an agent’s program replays that SQL
unchanged, so backtesting it before the date of its search tests a program
chosen with later data.
Good to know
- Each prediction reads every table as of one moment. Snowflake uses Time Travel and Databricks pins Delta table versions, so those tables need history; views are not supported.
- Local mode predicts numeric targets. A yes/no target such as
COUNT(results.*,0,60,days)=0needs hosted mode. - Your database bills the reads, including the key checks that run before extraction.
Next steps
Installation
The
nori-rel extras for PostgreSQL, Snowflake, and Databricks.Explainability
SHAP values, feature interactions, and partial dependence.