Producer#
#class Producer
Instances of the Producer
class act as variables in a rule or query context.
When the context is evaluated, all possible values for the variable are produced.
Instead of constructing Producer
instances directly, they are returned as the result of various operations.
The Producer
class is the base class for different kinds of producers, including:
Instance
, returned when you call aType
.InstanceProperty
, returned when you access a property of an object.Expression
, returned as the result of an operation on a producer, such as a mathematical or Boolean expression, or an aggregation.
Methods#
The following methods support mathematical operations on producers:
Name | Description | Returns |
---|---|---|
__add__() | Supports the + operator between producers and other values. | Expression |
__sub__() | Supports the - operator between producers and other values. | Expression |
__mul__() | Supports the * operator between producers and other values. | Expression |
__truediv__() | Supports the / operator between producers and other values. | Expression |
__floordiv__() | Supports the // operator between producers and other values. | Expression |
__pow__() | Supports the ** operator between producers and other values. | Expression |
__mod__() | Supports the % operator between producers and other values. | Expression |
The following methods support comparison operations on producers:
Name | Description | Returns |
---|---|---|
__eq__() | Supports == comparison between producers and other values. | Expression |
__ne__() | Supports != comparison between producers and other values. | Expression |
__ge__() | Supports >= comparison between producers and other values. | Expression |
__gt__() | Supports > comparison between producers and other values. | Expression |
__le__() | Supports <= comparison between producers and other values. | Expression |
__lt__() | Supports < comparison between producers and other values. | Expression |
Instances of Producer
support arbitrary attribute access
and can be used as a context manager
in a with
statement:
Name | Description | Returns |
---|---|---|
__getattribute__() | Get a property of an object. | InstanceProperty |
__enter__() | Enter the producer’s context. | None |
__exit__() | Exit the producer’s context. | None |
Example#
The key idea behind the Producer
class is that it is used to represent a variable
in a rule or query context:
#import relationalai as rai
# Create a model named 'people' with Person and Adult types.
model = rai.Model("people")
Person = model.Type("Person")
Adult = model.Type("Adult")
# Add some people to the model.
with model.rule():
# Type.add() returns an Instance, which is a producer.
alice = Person.add(name="Alice", age=8)
bob = Person.add(name="Bob", age=36)
# Instance producers have a .set() method for setting properties and
# additional types on objects.
bob.set(parent_of=alice)
# Create a rule that sets the Adult type on each person whose age is at least 18.
with model.rule():
# Calling a type returns an Instance producer.
person = Person() # person produces Person objects.
# person.age returns an InstanceProperty, which is also a producer.
# Comparing the age to 18 returns an Expression, yet another producer.
person.age >= 18 # Filter to people who are 18 or older.
person.set(Adult) # Set the adult type on the people who pass the filter.
You can think of the rule as executing once for each Person
object in the model.
Each line in the rule describes a step in a pipeline that the objects produced by person
pass through:
person
Produces aPerson
object.person.age >= 18
only lets through objects with an age of 18 or more.person.set(Adult)
sets theAdult
type on the objects that pass through.
The object for Alice never reaches the last step because her age is less than 18.
But the object for Bob does reach the last step, and the Adult
type is set on it.
Multiple producers may be mixed in the same rule or query:
## Get pairs of people where the first person is younger than the second.
with model.query() as select:
person1, person2 = Person(), Person()
person1.age < person2.age
response = select(person1.name, person2.name)
print(response.results)
# Output:
# name1 name2
# 0 Alice Bob
Both person1
and person2
produce Person
objects.
The query is evaluated for each pair of possible values for person1
and person2
, of which there are four:
- Alice and Alice
- Alice and Bob
- Bob and Alice
- Bob and Bob
Only the pair (Alice, Bob) passes through the comparison and into select()
since Alice is 8 and Bob is 36.
Producers can be used as context managers.
This is especially useful for Expression
producers, which can be used to create a subcontext that applies to a subset of objects:
#Minor = model.Type("Minor")
with model.rule():
person = Person()
# If the person's age is less than 18, set the Minor type.
with person.age < 18:
person.set(Minor)
# If the person's age is at least 18, set the Adult type.
with person.age >= 18
person.set(Adult)
Thinking of the rule as a pipeline, the with
statement creates a subcontext
whose contents only apply to objects for which the Expression
is true,
but doesn’t block objects from passing through to the rest of the rule.
For example, the Alice object passes through the first with
statement and gets the Minor
type set on it since she is 8.
Her object still passes through to the second with
statement, but the Adult
type is not set on her because the expression is false.
Bob, on the other hand, passes through the first with
statement without setting the Minor
type, but the Adult
type is set on him in the second with
statement.