Query a model with PyRel
If you have a local PyRel project for a deployed model, you can use PyRel to query the model. This guide shows you how to verify the deployment target and provides several examples of the kinds of queries you can run.
- Prerequisites
- Your have a local PyRel project that contains the code that defines the model, concepts, properties, and relationships you want to query. See See Install and run PyRel for installation details.
- Your model is deployed to a target schema. See Deploy a model if you need to deploy it.
- Your project connects to the same Snowflake account as the deployed model, and you can access the target schema. See Configure Snowflake authentication for help setting up and testing your connection.
Check your project and deployment target
Section titled “Check your project and deployment target”PyRel builds queries from the model definitions in your local project. The project’s deployment.public_schema setting identifies the Snowflake schema that contains the deployed model outputs.
From your model project, import its model object and inspect the profile and deployment schema:
from model.schema import model as m
print(m.config.active_profile)print(m.config.deployment.public_schema)Check that the printed schema matches the schema where PyRel deployed the model outputs you want to query.
This confirms which configuration PyRel loads, but it doesn’t confirm deployment.
If the target is wrong, choose the correct active profile or update deployment.public_schema in your project configuration.
If you haven’t deployed the model yet, see Deploy a model.
Import your model definitions in PyRel
Section titled “Import your model definitions in PyRel”We recommend keeping queries in a separate Python module from your model definitions. You can also write queries in a Jupyter notebook or an interactive Python session.
Import the model instance, concepts, and relationships from the module in your project that defines them.
In this example, that module is model.schema.
Use your module path and symbol names if they differ:
from model.schema import Company, Person, model as mWhen Model() has no config argument, PyRel loads the project’s default configuration, including its connection and deployment settings.
The name argument labels the Python object. It doesn’t select a deployed schema.
The deployment target comes from deployment.public_schema in the configuration you checked above.
Understand fragments and materialization
Section titled “Understand fragments and materialization”PyRel represents a query as a Fragment, which is a description of the values to return and the conditions they must satisfy.
Calls such as Model.select() and Fragment.select() create or refine a fragment. They don’t run the query.
Call Fragment.to_df() to execute the query and return its results as a pandas DataFrame.
Select values with select
Section titled “Select values with select”Select the properties you want in the result. alias() gives each returned column a stable, readable name:
from model.schema import Person, model as m
people = m.select( Person.id.alias("person_id"), Person.name.alias("person_name"),)people is a query fragment. It describes which values to return but doesn’t contain the result rows. PyRel retrieves those rows when you materialize the fragment with to_df(). You can also refine a fragment to select values from a relationship.
The works_at relationship connects each person to a company:
from model.schema import Company, Person, model as m
person_company = m.where(Person.works_at(Company))query_fragment = person_company.select( Person.id.alias("person_id"), Person.name.alias("person_name"), Company.id.alias("company_id"), Company.name.alias("company_name"),)The fragment describes one result row for each matching person-company relationship. It selects the IDs and names of both related concepts.
Materialize results with to_df
Section titled “Materialize results with to_df”Return each person-company relationship and print the result’s column names:
from model.schema import Company, Person, model as m
query_fragment = m.where(Person.works_at(Company)).select( Person.id.alias("person_id"), Person.name.alias("person_name"), Company.id.alias("company_id"), Company.name.alias("company_name"),)
df = query_fragment.to_df()print(df.columns.tolist())The output shows the DataFrame schema without inventing rows from your deployed model:
['person_id', 'person_name', 'company_id', 'company_name']Each row contains one matching person-company relationship.
If materialization fails, first confirm that deployment.public_schema in the configuration points to the intended schema and that the Python script runs from the project containing the model definitions. For connection or access issues, see Install and run PyRel.
Filter results with where
Section titled “Filter results with where”Use Model.where() to keep only the rows that match a condition, then select the values to return.
Filter by comparison
Section titled “Filter by comparison”Compare a property to a value supplied by your Python code:
from model.schema import Person, model as m
person_name = input("Person name: ").strip()query_fragment = m.where(Person.name == person_name).select( Person.id.alias("person_id"), Person.name.alias("person_name"),)df = query_fragment.to_df()The result contains people whose name equals the entered value. If no deployed person has that name, the DataFrame has no rows.
Filter by membership with .in_()
Section titled “Filter by membership with .in_()”Use Variable.in_() to keep values that match any item in a list:
from model.schema import Company, model as m
company_names = [ name.strip() for name in input("Company names, separated by commas: ").split(",") if name.strip()]if not company_names: raise ValueError("Enter at least one company name.")
query_fragment = m.where(Company.name.in_(company_names)).select( Company.id.alias("company_id"), Company.name.alias("company_name"),)df = query_fragment.to_df()The result contains only companies whose names appear in the entered list. If none of the entered names matches a deployed company, the DataFrame has no rows.
Rank and select top results with rank, asc, desc, and top
Section titled “Rank and select top results with rank, asc, desc, and top”Aggregates can rank companies by how many people have a works_at relationship with each company. Use aggregates.rank() with aggregates.desc() to rank the largest count first:
from relationalai.semantics.std import aggregatesfrom model.schema import Company, Person, model as m
people_per_company = ( aggregates.count(Person) .per(Company) .where(Person.works_at(Company)))
query_fragment = m.select( Company.name.alias("company_name"), people_per_company.alias("people_count"), aggregates.rank(aggregates.desc(people_per_company)).alias("people_rank"),)df = query_fragment.to_df()aggregates.rank() adds a rank column. It doesn’t sort the returned DataFrame. Use aggregates.asc() to rank smaller counts first, or sort the DataFrame after materialization.
Use aggregates.top() in where() to keep the top results. Here’s how to rank by the same per-company count:
from relationalai.semantics.std import aggregatesfrom model.schema import Company, Person, model as m
people_per_company = ( aggregates.count(Person) .per(Company) .where(Person.works_at(Company)))
query_fragment = ( m.select( Company.name.alias("company_name"), people_per_company.alias("people_count"), ) .where(aggregates.top(10, people_per_company)))df = query_fragment.to_df()The query returns the ten companies with the highest counts.
Deduplicate rows with distinct
Section titled “Deduplicate rows with distinct”Use distinct() to return unique values or unique combinations of selected values:
from model.schema import Company, Person, model as m
unique_companies = m.select(m.distinct(Company.name))
unique_person_company_pairs = m.where(Person.works_at(Company)).select( m.distinct(Person.name, Company.name))unique_companies returns each company name once. unique_person_company_pairs returns each person-company name pair once.
To deduplicate a multi-column row, include every selected value in the same distinct() call.
You can count unique values by passing a distinct value to aggregates.count():
from relationalai.semantics.std import aggregatesfrom model.schema import Company, model as m
query_fragment = m.select( aggregates.count(m.distinct(Company.name)).alias("unique_company_count"))df = query_fragment.to_df()Aggregate results with count and per
Section titled “Aggregate results with count and per”Use per() to group an aggregate by a concept or property. This query counts the people related to each company:
from relationalai.semantics.std import aggregatesfrom model.schema import Company, Person, model as m
people_per_company = ( aggregates.count(Person) .per(Company) .where(Person.works_at(Company)))query_fragment = m.select( Company.name.alias("company_name"), people_per_company.alias("people_count"),)df = query_fragment.to_df()The DataFrame has one row per company with a matching relationship and a count for that company. The count and rows depend on your deployed model.
Export results to Snowflake tables with into and exec
Section titled “Export results to Snowflake tables with into and exec”Optional: export a query fragment to a Snowflake table
Use Fragment.into() to set the destination, then Fragment.exec() to run the export.
Replace the placeholder with a fully qualified destination table name. The destination schema must allow you to create or replace the table.
An existing target is replaced by default. update=True requests an update export where supported.
Each code block builds its own query fragment and destination table, so you can run either one independently:
from model.schema import Company, Person, model as m
query_fragment = m.where(Person.works_at(Company)).select( Person.id.alias("person_id"), Person.name.alias("person_name"), Company.id.alias("company_id"), Company.name.alias("company_name"),)
out = m.Table("<OUTPUT_DB>.<OUTPUT_SCHEMA>.<OUTPUT_TABLE>")query_fragment.into(out).exec()from model.schema import Company, Person, model as m
query_fragment = m.where(Person.works_at(Company)).select( Person.id.alias("person_id"), Person.name.alias("person_name"), Company.id.alias("company_id"), Company.name.alias("company_name"),)
out = m.Table("<OUTPUT_DB>.<OUTPUT_SCHEMA>.<OUTPUT_TABLE>")query_fragment.into(out, update=True).exec()You can also use a configured short table name with m.Table("MY_NAMED_EXPORT"). See Configure PyRel and the Model.Table() API reference for destination configuration and optional destination schemas.
Where to go next
Section titled “Where to go next”Choose a guide based on what you want to do next: