Open awilde27 opened 3 years ago
Hi, thanks for posting the question. There is no good or wrong answer. But, I think your example would be more efficient if you write all the rules in a single ruleset and use forward chaining by making assertions.
Below is a very simple example: asserting "Kermit eats flies" and "Kermit lives in water" will trigger the assertion "Kermit is a frog", which will trigger the assertion "Kermit is green".
Internally the rules engine will remember the facts you have asserted by building a decision tree (Rete), the decision to assert "Kermit is a frog" right after asserting "Kermit lives in water" is optimal as all the facts don't need to be re-evaluated again.
from durable.lang import *
with ruleset('animal'):
@when_all(c.first << (m.predicate == 'eats') & (m.object == 'flies'),
(m.predicate == 'lives') & (m.object == 'water') & (m.subject == c.first.subject))
def frog(c):
c.assert_fact({ 'subject': c.first.subject, 'predicate': 'is', 'object': 'frog' })
@when_all((m.predicate == 'is') & (m.object == 'frog'))
def green(c):
c.assert_fact({ 'subject': c.m.subject, 'predicate': 'is', 'object': 'green' })
@when_all(+m.subject)
def output(c):
print('Fact: {0} {1} {2}'.format(c.m.subject, c.m.predicate, c.m.object))
assert_fact('animal', { 'subject': 'Kermit', 'predicate': 'eats', 'object': 'flies' })
assert_fact('animal', { 'subject': 'Kermit', 'predicate': 'lives', 'object': 'water' })
Hope this helps.
Thank you for the quick response. I understand the idea here that I can forward-chain assertions. Given your example, I think the additional element I have to incorporate here is to forward chain specific attributes of c.m
so that when a rule asserts a new fact I only include relevant data so that a rule I wish to trigger lower in the set gets triggered as opposed to getting caught in an infinite loop. What I find tricky is organizing a ruleset for scale and readability. Nevertheless, it might be a bit more overhead on my part, but agreed it is a more efficient implementation.
I think it makes sense, within a rule, to assert a fact out to a separate ruleset dedicated to simply for storing consequents triggered within the main ruleset. This seems necessary, as the engine will only store the data that a fact passed to the ruleset as opposed to the consequent. Will try this approach and follow up with any further questions - appreciate the insight.
Hi @jruizgit, brilliant package you've created here.
I have a use case in which I'm using
durable_rules
to a construct decision rule tree, ideally where each node is its own ruleset and the further down the tree, the more sophisticated the consequents (in my case, insights or recommendations). A flowchart seems like a great candidate, but the only catch is that my use case is stateless, i.e. when I post an event I need it to flow through entirely rather than be queued to the next stage.I'm still learning and thinking through the abilities of
durable_rules
, but my intuition tells me I need something between a set of rulesets and a flowchart, and something in between a fact assertion and an event posting.What I'd appreciate insight on:
c.s.result_stack
which seemed to work until I posted an event to a ruleset which posted that same event to a third.For this dummy example, you can assume I'm posting data that contains the same k attributes each time, uniqueness exists for
item_name
.Thank you in advance.