Start Here
Begin your RelationalAI (RAI) journey by setting up a development environment.
Start in Snowflake Set up locallyStart Here
Begin your RelationalAI (RAI) journey by setting up a development environment.
Start in Snowflake Set up locallyWith the RAI Native App installed in Snowflake, you can use the relationalai
Python package to turn stacks of data into a web of meaning—by modeling the entities, relationships, and rules that drive your application.
Create a model.
First, import relationalai
and create a Model
object:
import relationalai as rai
model = rai.Model("SupplyChainModel")
Then, use model.Type()
to define entity types derived from your Snowflake tables, and .define()
to model the relationships between them.
For example, a simple supply chain model might have the following entity types and relationships:
import relationalai as rai
model = rai.Model("SupplyChainModel")
# DECLARE ENTITY TYPES.# You can declare entity types from Snowflake tables. Data from these tables# are used to answer queries about the model.Product = model.Type("Product", source="<my_db>.<my_schema>.products")Order = model.Type("Order", source="<my_db>.<my_schema>.orders")Supplier = model.Type("Supplier", source="<my_db>.<my_schema>.suppliers")
# DEFINE RELATIONSHIP PROPERTIES# "Product contained_in Order" where Product.id == Order.product_idProduct.define(contained_in=(Order, "id", "product_id"))# Properties can be one-to-one or one-to-many.Product.contained_in.has_many()
# "Order fulfilled_by Supplier" where Order.supplier_id == Supplier.id# fulfilled_by is a one-to-one relationship since .has_many() is not called.Order.define(fulfilled_by=(Supplier, "supplier_id", "id"))
Now you can use the model.rule()
context manager to define rules that generate new entities and properties based on what you’ve already modeled:
import relationalai as raifrom relationalai.std import aggregates # <-- Add this line>
model = rai.Model("SupplyChainModel")
Product = model.Type("Product", source="<my_db>.<my_schema>.products")Supplier = model.Type("Supplier", source="<my_db>.<my_schema>.suppliers")Order = model.Type("Order", source="<my_db>.<my_schema>.orders")
# DECLARE A NEW ENTITY TYPE.SingleSourceProduct = model.Type("SingleSourceProduct")
8 collapsed lines
# "Product contained_in Order" where Product.id == Order.product_idProduct.define(contained_in=(Order, "id", "product_id"))# Properties can be one-to-one or one-to-many.Product.contained_in.has_many()
# "Order fulfilled_by Supplier" where Order.supplier_id == Supplier.id# fulfilled_by is a one-to-one relationship since .has_many() is not called.Order.define(fulfilled_by=(Supplier, "supplier_id", "id"))
# WRITE A RULE TO DEFINE THE NEW ENTITY TYPE.# "Product is SingleSourceProduct" if it has exactly one Supplierwith model.rule(): product = Product() supplier = product.supplied_by aggregates.count(supplier, per=[product]) == 1 product.set(SingleSourceProduct)
# WRITE A RULE TO DEFINE A NEW PROPERTY.# "Product supplied_by Supplier" where Product.contained_in.fulfilled_by == Supplierwith model.rule(): product = Product() order = product.contained_in supplier = order.fulfilled_by product.supplied_by.add(supplier)
Use a Reasoner.
You can extend your model further by using reasoners with advanced AI capabilities to uncover insights that traditional SQL can’t express.
For example, you can import the relationalai.std.graphs
module to use RAI’s graph reasoner to analyze relationships between entities in your model, such as identifying suppliers who sell similar products:
import relationalai as raifrom relationalai.std import aggregates, graphs # <-- Edit this line
model = rai.Model("SupplyChainModel")
Product = model.Type("Product", source="<my_db>.<my_schema>.products")Supplier = model.Type("Supplier", source="<my_db>.<my_schema>.suppliers")Order = model.Type("Order", source="<my_db>.<my_schema>.orders")SingleSourceProduct = model.Type("SingleSourceProduct")
# DECLARE A NEW ENTITY TYPE.SimilarSuppliers = model.Type("SimilarSuppliers")
22 collapsed lines
# "Product contained_in Order" where Product.id == Order.product_idProduct.define(contained_in=(Order, "id", "product_id"))# Properties can be one-to-one or one-to-many.Product.contained_in.has_many()
# "Order fulfilled_by Supplier" where Order.supplier_id == Supplier.id# fulfilled_by is a one-to-one relationship since .has_many() is not called.Order.define(fulfilled_by=(Supplier, "supplier_id", "id"))
# "Product is SingleSourceProduct" if it has exactly one Supplierwith model.rule(): product = Product() supplier = product.supplied_by aggregates.count(supplier, per=[product]) == 1 product.set(SingleSourceProduct)
# "Product supplied_by Supplier" where Product.contained_in.fulfilled_by == Supplier with model.rule(): product = Product() order = product.contained_in supplier = order.fulfilled_by product.supplied_by.add(supplier)
# DEFINE A GRAPH.graph = graphs.Graph(model, undirected=True)# Define nodes from the union of the Product and Supplier types.graph.Node.extend(Product | Supplier)# Define edges between Products and their Suppliersgraph.Edge.extend(Product.supplied_by)
# WRITE A RULE THAT USES THE GRAPH TO DEFINE THE NEW ENTITY TYPE.# Conditionally define SimilarSuppliers using the Jaccard similarity algorithm.with model.rule(): supplier1, supplier2 = Supplier(), Supplier() score = graph.compute.jaccard_similarity(supplier1, supplier2) score > 0.5 suppliers = SimilarSuppliers.add(supplier1=supplier1, supplier2=supplier2) suppliers.set(similarity_score=score)
Query the model and export data.
Query your model using the model.query()
context manager to get a pandas DataFrame with the results:
import relationalai as raifrom relationalai.std import aggregates, alias, graphs # <-- Edit this line
model = rai.Model("SupplyChainModel")
47 collapsed lines
# Declare entity types.Product = model.Type("Product", source="<my_db>.<my_schema>.products")Supplier = model.Type("Supplier", source="<my_db>.<my_schema>.suppliers")Order = model.Type("Order", source="<my_db>.<my_schema>.orders")# Types without source tables must be defined later in a rule.SingleSourceProduct = model.Type("SingleSourceProduct")SimilarSuppliers = model.Type("SimilarSuppliers")
# Define relationship properties.# "Product contained_in Order" where Product.id == Order.product_idProduct.define(contained_in=(Order, "id", "product_id"))# Properties can be one-to-one or one-to-many.Product.contained_in.has_many()
# "Order fulfilled_by Supplier" where Order.supplier_id == Supplier.id# fulfilled_by is a one-to-one relationship since .has_many() is not called.Order.define(fulfilled_by=(Supplier, "supplier_id", "id"))
# Define rules to derive new entities and properties.# "Product is SingleSourceProduct" if it has exactly one Supplierwith model.rule(): product = Product() supplier = product.supplied_by aggregates.count(supplier, per=[product]) == 1 product.set(SingleSourceProduct)
# "Product supplied_by Supplier" where Product.contained_in.fulfilled_by == Supplier with model.rule(): product = Product() order = product.contained_in supplier = order.fulfilled_by product.supplied_by.add(supplier)
# Define a graph.graph = graphs.Graph(model, undirected=True)# Define nodes from the union of the Product and Supplier types.graph.Node.extend(Product | Supplier)# Define edges between Products and their Suppliersgraph.Edge.extend(Product.supplied_by)
# Conditionally define SimilarSuppliers using the Jaccard similarity algorithm.with model.rule(): supplier1, supplier2 = Supplier(), Supplier() score = graph.compute.jaccard_similarity(supplier1, supplier2) score > 0.5 suppliers = SimilarSuppliers.add(supplier1=supplier1, supplier2=supplier2) suppliers.set(similarity_score=score)
# QUERY THE MODEL.# What are the potential backup suppliers for products with a single supplier?with model.query() as select: product = SingleSourceProduct() supplier = product.supplied_by potential_supplier = SimilarSuppliers(supplier1=supplier).supplier2 response = select( alias(product.id, "product_id"), alias(potential_supplier.id, "potential_supplier_id"), )
# USE THE RESULTS AS A PANDAS DATAFRAME.response.results.head(5)
Query your model using the model.query(format="snowpark")
context manager to get a Snowpark DataFrame with the results that can be used to write results to a Snowflake table or view:
import relationalai as raifrom relationalai.std import aggregates, alias, graphs # <-- Edit this line
model = rai.Model("SupplyChainModel")
47 collapsed lines
# Declare entity types.Product = model.Type("Product", source="<my_db>.<my_schema>.products")Supplier = model.Type("Supplier", source="<my_db>.<my_schema>.suppliers")Order = model.Type("Order", source="<my_db>.<my_schema>.orders")# Types without source tables must be defined later in a rule.SingleSourceProduct = model.Type("SingleSourceProduct")SimilarSuppliers = model.Type("SimilarSuppliers")
# Define relationship properties.# "Product contained_in Order" where Product.id == Order.product_idProduct.define(contained_in=(Order, "id", "product_id"))# Properties can be one-to-one or one-to-many.Product.contained_in.has_many()
# "Order fulfilled_by Supplier" where Order.supplier_id == Supplier.id# fulfilled_by is a one-to-one relationship since .has_many() is not called.Order.define(fulfilled_by=(Supplier, "supplier_id", "id"))
# Define rules to derive new entities and properties.# "Product is SingleSourceProduct" if it has exactly one Supplierwith model.rule(): product = Product() supplier = product.supplied_by aggregates.count(supplier, per=[product]) == 1 product.set(SingleSourceProduct)
# "Product supplied_by Supplier" where Product.contained_in.fulfilled_by == Supplier with model.rule(): product = Product() order = product.contained_in supplier = order.fulfilled_by product.supplied_by.add(supplier)
# Define a graph.graph = graphs.Graph(model, undirected=True)# Define nodes from the union of the Product and Supplier types.graph.Node.extend(Product | Supplier)# Define edges between Products and their Suppliersgraph.Edge.extend(Product.supplied_by)
# Conditionally define SimilarSuppliers using the Jaccard similarity algorithm.with model.rule(): supplier1, supplier2 = Supplier(), Supplier() score = graph.compute.jaccard_similarity(supplier1, supplier2) score > 0.5 suppliers = SimilarSuppliers.add(supplier1=supplier1, supplier2=supplier2) suppliers.set(similarity_score=score)
# QUERY THE MODEL.# Who are the potential backup suppliers for products with a single supplier?with model.query(format="snowpark") as select: product = SingleSourceProduct() supplier = product.supplied_by potential_supplier = SimilarSuppliers(supplier1=supplier).supplier2 response = select( alias(product.id, "product_id"), alias(potential_supplier.id, "potential_supplier_id"), )
# WRITE THE QUERY RESULTS TO A SNOWFLAKE TABLE.response.results.write.save_as_table("<my_db>.<my_schema>.potential_backup_suppliers")
Use the @model.export()
decorator function to export a query as a Snowflake SQL stored procedure that can be called from any Snowflake client:
import relationalai as raifrom relationalai.std import aggregates, alias, graphs # <-- Edit this line
model = rai.Model("SupplyChainModel")
47 collapsed lines
# Declare entity types.Product = model.Type("Product", source="<my_db>.<my_schema>.products")Supplier = model.Type("Supplier", source="<my_db>.<my_schema>.suppliers")Order = model.Type("Order", source="<my_db>.<my_schema>.orders")# Types without source tables must be defined later in a rule.SingleSourceProduct = model.Type("SingleSourceProduct")SimilarSuppliers = model.Type("SimilarSuppliers")
# Define relationship properties.# "Product contained_in Order" where Product.id == Order.product_idProduct.define(contained_in=(Order, "id", "product_id"))# Properties can be one-to-one or one-to-many.Product.contained_in.has_many()
# "Order fulfilled_by Supplier" where Order.supplier_id == Supplier.id# fulfilled_by is a one-to-one relationship since .has_many() is not called.Order.define(fulfilled_by=(Supplier, "supplier_id", "id"))
# Define rules to derive new entities and properties.# "Product is SingleSourceProduct" if it has exactly one Supplierwith model.rule(): product = Product() supplier = product.supplied_by aggregates.count(supplier, per=[product]) == 1 product.set(SingleSourceProduct)
# "Product supplied_by Supplier" where Product.contained_in.fulfilled_by == Supplier with model.rule(): product = Product() order = product.contained_in supplier = order.fulfilled_by product.supplied_by.add(supplier)
# Define a graph.graph = graphs.Graph(model, undirected=True)# Define nodes from the union of the Product and Supplier types.graph.Node.extend(Product | Supplier)# Define edges between Products and their Suppliersgraph.Edge.extend(Product.supplied_by)
# Conditionally define SimilarSuppliers using the Jaccard similarity algorithm.with model.rule(): supplier1, supplier2 = Supplier(), Supplier() score = graph.compute.jaccard_similarity(supplier1, supplier2) score > 0.5 suppliers = SimilarSuppliers.add(supplier1=supplier1, supplier2=supplier2) suppliers.set(similarity_score=score)
# EXPORT A QUERY AS A STORED PROCEDURE.# Who are the potential backup suppliers for products with a single supplier?@model.export("<my_db>.<my_schema>")def potential_backup_suppliers() -> tuple[int, float]: product = SingleSourceProduct() supplier = product.supplied_by potential_supplier = SimilarSuppliers(supplier1=supplier).supplier2 return potential_supplier.id, potential_supplier.similarity_score
# CALL THE STORED PROCEDURE IN A SQL WORKFLOW.# CALL <my_db>.<my_schema>.potential_backup_suppliers(12345);
Kickstart your RAI journey with sample notebooks for real-world examples and use cases.
Deepen your understanding of RelationalAI with our comprehensive guides that cover core concepts, basic functionality, and advanced topics.