ulfurinn / wongi-engine Goto Github PK
View Code? Open in Web Editor NEWA rule engine written in Ruby.
License: MIT License
A rule engine written in Ruby.
License: MIT License
Are there any temporal operations where I could for example find the latest fact based on a date.
So for example:
Claim1, "is", "Claim"
Claim2, "is", "Claim"
Claim3, "is", "Claim"
Claim1, "dateofservice", 1/1/2016
Claim2, "dateofservice", 2/1/2016
Claim3, "dateofservice", 3/1/2016
Can I ask the engine to return the latest Claim or the earliest Claim?
how active is wongi:engine development? I came from the Drools background and its development is very active.
we're in the process of moving to Ruby on Rails and wongi:engine is a possible replacement for Drools. I'm wondering how active is it in term of development and maintenance since we plan to use it in production.
Thanks
Hi,
I have a situation where I need to generate conditions for the rule dynamically based on the user input. For example, this is what am trying to do.
def convert(title, variables)
engine.rule title do |variables|
forall {
has :_, :id, :Id
variables.each do |v|
has :Id, v.downcase.to_sym, v.capitalize.to_sym
end
}
end
end
Similarly for other matchers after has
, I want to dynamically set them. However seems like I can't pass any of my variables into the rule block. Is there anyway of doing this? Can I extend the DSL for this functionality? Based on the documentation, it seems that the DSL extension is only for actions. Thanks.
Hey there, I'm new to rule engines and the Rete algorithm. Learning about it and reading your code has been really fun. Anyway, now that I'm playing around with some rules I was wondering if it were possible to programmatically create new facts based on variables. In other words, is something similar to this supported?
Note: using gen
to illustrate what I'm doing, but aware it won't work since it supports static or variable object values.
engine.rule "example" do
forall {
has :A, "some_value", :B
}
make {
gen :A, "some_other_value", :B + 1
}
end
engine << ["test", "some_value", 10]
# resulting in creation of ["test", "some_other_value", 11]
Perhaps this should be done with make
and action
? Although then it seems like you'd lose easy access to your template variables.
I suppose you could do token.wme.(subject|predicate|object)
:
engine.rule "example" do
forall {
has :A, "some_value", :B
}
make {
action { |token| engine << [token.wme.subject, "some_other_value", token.wme.object + 1] }
}
end
Is there a better or more appropriate way? It's also possible that my question is misinformed. Either way, thanks for your time and again, appreciate the work you've done :) Let me know if the example is too contrived and I'd be glad to conjure up a more realistic one.
require 'wongi-engine'
include Wongi::Engine::DSL
class MActionClass
def execute(token)
p 'execute'
end
def deexecute(token)
p 'deexecute'
end
end
engine = Wongi::Engine.create
engine.rule 'test' do
forall {
has :A, :friend, :B
}
make {
action MActionClass
}
end
engine << ['tester', :friend, 'tester2']
engine.retract ['tester', :friend, 'tester2']
## output
# "execute"
# "execute"
How does deexecute work ?
I have used greater
and less
matchers and I can't compare with it.
has :P, "is", :B
greater :B, 10
is not working, says a String cannot be compared.
I would like to try wongi-engine but I get some problems to set it.
I am used to ruleby where I can easily access fields in the OpenStruct objects I want to put in the facts base and do some comparison on them to trigger rules.
I want to be able to see if a node has already recorded an error , and from there trigger an action, and depending on the type of error, remove the facts.
I wonder how I can write the "has" or other matchers.
Each object has a box method so I would like to do obj1.box == obj2.box
and also some other comparisons on other fields too
Thanks
RenΓ©
Hello,
I'm trying to use ANY { option {}} and getting this error:
gems/wongi-engine-0.2.7/lib/wongi-engine/dsl/any_rule.rb:14:in 'option': uninitialized constant Wongi::Engine::DSL::AnyRule::VariantRule (NameError)
Need help in implementing this use case. Say user hate yogurt or cheese or any other milk product, need to generate a triplet {:User, "Milk", :Product}. Unable to make it work and Variant Rule error is also stoping to move forward
milk_products = WEngine.rule "milk-products" do
forall {
any {
option {
has :User, "yogurt", :Product
has :User, "cheese", :Product
}
}
}
make {
gen :User, "Milk", :Product
}
end
10.times{|i| engine << [i, :is_number, true]}
engine.rule 'segregate' do
forall {
has :Number, :is_number, true
}
make {
action { |token|
number = token[:Number]
engine << [number, :is_even, true]
engine.retract [number, :is_number, true]
}
}
end
engine.each :, :, :true do |item|
puts item
end
This will print all the even as :is_even true and leaves all the odds as :is_number true - even though I didn't test for that. ie. it skips every other one.
My use case is, let us say, that if a given hash has a particular value for a key, I have to return some other key from the hash. Basically, if I want to use this in an already existing repo deployed on VMs, how would I integrate that?
ds = Network.new
ds << ruleset {
rule "type" do
forall {
has :A, :type, "Goods"
}
make {
action do
return true
end
end
}
return_value = ds << WME.new( "Sample Product", :type, "Goods" )
How would I achieve this?
engine = Wongi::Engine.create
engine << Wongi::Engine::DSL::rule :active_less_than_1_of_last_7_days do
for_all {
has :last_capture_at, :CustomerId, :LastCaptureAt
any {
option {
same :LastCaptureAt, nil
}
option {
assign :SevenDaysAgo do
Time.current - 7.days
end
diff :LastCaptureAt, nil
less :LastCaptureAt, :SevenDaysAgo
}
}
}
make {
gen :decline_reason, :CustomerId, 'active_less_than_1_of_last_7_days'
}
end
engine << [:last_cature_at, 'token1', Time.current - 7.days]
callstack:
/Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/string/conversions.rb:54:in 'parse': invalid date (ArgumentError)
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/string/conversions.rb:54:in 'to_datetime'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/date_time/calculations.rb:157:in '<=>'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/core_ext/time/calculations.rb:241:in 'compare_with_coercion'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/activesupport-4.1.15/lib/active_support/time_with_zone.rb:214:in '<=>'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/wme.rb:78:in '=='
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/wme.rb:78:in 'match_member'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/wme.rb:52:in '=~'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'block in find'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:6:in '<<'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:6:in 'block (2 levels) in new'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:5:in 'each'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/enumerators.rb:5:in 'block in new'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'each'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'each'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'find'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:334:in 'find'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:127:in 'real_assert'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:86:in 'block in process_cascade'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:82:in 'each'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:82:in 'process_cascade'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/data_overlay.rb:63:in 'assert'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:113:in 'assert'
from /Users/meghanm/.rvm/gems/ruby-2.3.1/gems/wongi-engine-0.2.9/lib/wongi-engine/network.rb:203:in '<<'
from ./script/wongi-test.rb:137:in 'load_facts'
from ./script/wongi-test.rb:183:in '<main>'
I have a rule like:
eligible_person = rule "Eligible person" do
forall {
has :Person, "sex", "Male"
has :_, "age", :age
greater :age, 50
}
make {
gen :Person, "eligible_person", true
}
end
and another rule like:
identify_thing = rule "Identify thing" do
forall {
has :User, "role", "special_role_for_this_thing"
maybe :Person, "eligible_person", :EligiblePerson
maybe :Person, "special_marker", :SpecialMarker
maybe :Person, "other_thing", :OtherThing
assert do |token|
(token[:EligiblePerson] == true && token[:SpecialMarker] != nil) || (token[:OtherThing] != nil && token[:OtherThing] > 25)
end
}
end
I load the engine with facts iteratively, but the effect is basically as follows:
engine = Wongi::Engine.create
engine << ["Joe", "sex", "Male"]
engine << ["Joe", "age", 61]
engine << ["user", "role", "special_role_for_this_thing"]
Then I add the rules roughly like the following:
rules.each do |rule|
engine << rule
end
They run, but when I pry into the assert
in "Identify thing"
I see that token[:EligiblePerson] = nil
. I'm looking for engine.productions["Identify thing"].size > 0
and can't seem to make the rules work together. However, when I step through Wongi with the debugger in pry, I can see the template for gen
making EligiblePerson, and apparently adding it to the engine. But, I can't access that fact for some reason. When I call:
engine.facts.map{|fact| p fact}
I see all of the facts I entered with <<
, but not the one made by gen
.
Any thoughts on what I'm doing wrong?
Edit for catching nil on token[:OtherThing]
I was able to paste this all into the console to reproduce the behavior I'm seeing in my actual application.
I am creating a rule that should generate new facts.
rule :get_customer_facts do
for_all {
has :base_fact, :customer_id, :CustomerId
assign :Customer do |token|
Customer.find(token[:CustomerId])
end
assign :IsFrozen do |token|
token[:Customer].frozen? # frozen? returns false
end
}
make {
gen :CustomerId, :customer_is_frozen, :IsFrozen
}
When .frozen? returns false in the :IsFrozen assignment, then I get the following error:
Wongi::Engine::DefinitionError: unbound variable IsFrozen in token TOKEN [ 70248794866740 parent=70248783279520 CustomerId => object of {:base_fact :customer_id 40000010} Customer => #<Customer::Unit:0x007fc8238c6b10> IsFrozen => false ]
Pretty extensive users of wongi-engine. Glad to see that declarative collections are on the path to becoming first class with collectors.
Two items that would make our lives easier if they were available.
1 #map and #inject for tokens matching a rule
Consider this circumstance
facts_matching_my_rule = rules[:my_rule].tokens
facts_matching_my_rule.each do |token|
# yada yada
end
Many times I find myself wishing that #map and #inject also worked in these circumstances. I imagine that #map! isn't feasible although it does sound appealing.
2 forall_eval (or if this already exists, then documentation and examples)
The wongi-engine rules can be frustratingly incompatible with a notion of rule inheritance - and while you can combine queries and rules to, in some cases, achieve single inheritance it would really be more idiomatic if we had access to the equivalent of instance_eval for a particular rule - it seems that the notion of a rule's singleton is roughly parallel to a class's singleton. Even if the notion of runtime polymorphism of rules (specifically the forall sections) is infeasible then the addition of an explicit rule inheritance operator would be splendid.
Hi,
Is it possible to create a rule with dynamic conditions? Something like the following...
engine = Wongi::Engine.create
engine << ["Joe", "gender", "Male"]
engine << ["Joe", "age", 61]
# Records of conditions with predicates and constraints, as defined by the user.
conditions = Condition.all
el = engine.rule( "Eligible person" ) do
forall {
has :Person, "age", :Age
conditions.each do |condition|
#add condition here, e.g. `has :_, condition.predicate, condition.match_value`
end
}
end
Thanks!
Hello.
Getting known with your engine I tried this simple example with opposite rules. As I concern in result two new facts should appear:
Bob, approved, true,
Alice, approved, false.
But the result is strange:
Bob, approved, true,
Bob, approved, false.
Is it a bug or i do something wrong, can you please explain this situation. Thanks in advance.
Regards,
Fokin Eugene.
require 'wongi-engine'
ruleset do
name "Example"
rule "more" do
forall {
has :Name, "age", :Age
assert :Age do |age|
age >= 10
end
}
make {
action { |token|
puts "#{token[:Name]} is approved"
}
gen :Name, "approved", true
}
end
rule "less" do
forall {
has :Name, "age", :Age
assert :Age do |age|
age < 10
end
}
make {
action { |token|
puts "#{token[:Name]} is not approved"
}
gen :Name, "approved", false
}
end
rule "self-printer" do
forall {
has :A, :B, :C
}
make {
action { |token|
puts "%s, %s, %s" % [ token[ :A ], token[ :B ], token[ :C ] ]
}
}
end
end
engine = Wongi::Engine.create
engine << Wongi::Engine::Ruleset["Example"]
engine << ["Alice","age",5]
engine << ["Bob","age",15]
This is something I've had on my mind for a while, and going through old tickets I saw similar concerns from other people, so I decided to get something written.
Generally, a rule engine should be compiled once and reused, because compiling a large rule base can be expensive. However, up until now, data was stored inside logic elements, which means that if you do want to reuse an engine instance, you need to retract all asserted facts, will which retrigger rule execution, which is also expensive.
Data overlays separate facts from logic elements, allowing a user to quickly wipe data from en engine instance.
Overlays can be stackable indefinitely, for data with different lifetimes. #<<
called on the engine instance will add facts to #default_overlay
, which is globally visible and permanent.
This is intended for 0.2.0.
I noticed that the handling of tokens has changed between v0.0.13 and .14. How are tokens meant to be used in situations like:
if my_rule_name.tokens.size > 0
return stuff
end
I can see that the token code gained a new method here and changes a bit here.
Could you give me some advice on how to use the new version so I'm not stuck on v0.0.13?
If you can give me a thorough explanation, I would be happy to help update the docs.
engine.rule "whatever" do
forall {
...
}
make {
gen :This, :Will, :Work
action { |token|
gen :This, :Fails, :Silently
}
}
end
I'm guessing having this not work inside action kind of required. But having it fail silently makes me sad.
Hi there,
Overlays are fantastic but it seems like assignment nodes should take them into account. If you try adding an assign to that new overlay spec you'll see the test fail. I got around it by passing in the token.wme to the new token in assignment_node's beta_activate.
def beta_activate token, wme = nil, assignments = { }
children.each do |child|
child.beta_activate Token.new( child, token, token.wme, { @variable => @body.respond_to?(:call) ? @body.call(token) : @body } )
end
end
This makes the overlay test pass, you probably have a better way though, any thoughts?
Hi,
I have many criteria as rules and I want to match a user to these criteria. e.g.
engine << ["user", "age", 20]
engine << ["user", "state", "CA"]
engine << ["user", "weight", 130]
and I have many rules like the following
forall {
has :A, "age", :Age
less :Age, 30
greater :Age, 20
has :A, "state", "CA"
}
At any point in time there will only be one user.
Is there a way to do this matching more efficiently without having to loop through each rule? Typically one would match a rule to many subjects but I want to do this the other way around, find which rules the subject agrees with.
I tried to have the criteria expressed as facts and the user attributes be rules but I have found it to be difficult to construct combinations.
Thanks!
Hi,
We are considering using wongi-engine, but we are having a hard time understanding the code since there are no comments. Are there any plans to comment the code?
This is my use case:
I have many events in the system like:
user1, create, meeting1
meeting1, has, tag1
meeting1, has, tag2
meeting1, has, tag3
user1, create, meeting2
user2, create, meeting3
The rules are dynamic because is based in the interest of each user. Example:
user3 wants to know of create meetings but with tag 1 or 2.
Now, my questions and search for suggestions. I guess there's a way to write rules like the example case for user3. So not a problem. But:
.rvm/gems/ruby-2.2.0/bundler/gems/wongi-engine-ee696450d9af/lib/wongi-engine/wme.rb:129: warning: Comparable#== will no more rescue exceptions of #<=> in the next release.
I'm not quite sure how to fix this. @ulfurinn any thoughts?
This example in the tutorial does not seem to work when I combine rules:
my_ruleset = ruleset {
rule "rule 1" do
...
end
rule "rule 2" do
...
end
}
engine << my_ruleset
I get this:
undefined method `ruleset' for main:Object (NoMethodError)
Any help or clarity in the doc would be appreciated.
Hi,
I'm trying to use the any matcher to include "or" conditions, but the engine only matches if the the first option rule is verified.
engine = Wongi::Engine.create
ruleset "my Rules" do
rule "error en rojo" do
forall {
any {
option {
has :A, :scenario, "OT en rojo"
}
option {
has :A, :msisdn, "12345678"
}
}
has :A, :cliente, "manolito"
}
make {
action {
puts "Es un error en rojo"
}
}
end
end
engine << Wongi::Engine::Ruleset["my Rules"]
engine << ["123456", :msisdn, "12345678"]
engine << ["123456", :cliente, "manolito"]
engine << ["123456", :scenario, "OT en rojo"]
Output: Es un error en rojo
engine = Wongi::Engine.create
ruleset "my Rules" do
rule "error en rojo" do
forall {
any {
option {
has :A, :scenario, "OT en rojo"
}
option {
has :A, :msisdn, "12345678"
}
}
has :A, :cliente, "manolito"
}
make {
action {
puts "Es un error en rojo"
}
}
end
end
engine << Wongi::Engine::Ruleset["my Rules"]
engine << ["123456", :msisdn, "12345678"]
engine << ["123456", :cliente, "manolito"]
engine << ["123456", :scenario, "OT en rojos"]
Output:
Hi,
in my project am using rails and used below code to check the budget is going positive or not . But the variable comparison is not working . Any ideas?
@@engine.rule("Positive Budget Rule") do
forall {
has :id, "budget-expect", :num1
has :id, "budget-actual", :num2
greater :num1, :num2
}
make {
gen "result", "Postitive Trends", :id
}
end
Hello,
In the new version of wongi (v0.1.1) I note that you open Object
class and include Wongi::Engine::DSL
module.
class Object
warn "[DEPRECATION] Future versions of wongi-engine will not define dsl on Object. Please `include Wongi::Engine::DSL` going forward."
include Wongi::Engine::DSL
end
It caused a problem with faraday
gem. Faraday executes the code below:
def url(path, params = nil)
if path.respond_to? :query
if query = path.query
path = path.dup
path.query = nil
end
...
The query
method is called without params, raising this exception:
wrong number of arguments (0 for 1)
I think that was not a good idea open the Object
class and include Wongi::Engine::DSL
module. I had to rollback version to fix my problem.
I know this may fall far from what Wongi is intending, but I was hoping you can help me sort out how to do this ;)
We have a bunch of rules that are heavily dependent on certain data being present. Specifically, our rules state things like given form "x" the user answered question "y" in a particular way.
We often run into simple things like name mismatches between the rules and the data.
I'd like to lint the data/rules by confirming that it is possible for a given rule to fire.
So, given something like:
forall {
has :Event, 'program_name', "Level 1 Coaching Certification"
has :Event, 'activity_name', "Redo Exam #1"
}
I want to quickly run through and make sure that the program referenced does indeed include an activity with that name.
So, in a sense, I want to run rules on rules ;) I'd love to setup a "linter ruleset", then load my normal production rulesets as facts to check.
I know that sounds crazy... is it doable?
Thanks in advance!
See #61
No idea why, but when we use overlays with a statement generator we are finding that the token doesn't include an overlay.
This fix resolves the problem, but I imagine it'll have some terrible consequence in the future that we haven't noticed yet...
We are invoking the statement generator from within an action like this:
fact = Wongi::Engine::Template.new(membership, key, value)
generator = Wongi::Engine::DSL::Action::StatementGenerator.new fact
generator.rete = rete
generator.production = production
generator.execute token
Great lib!
Is there any way to persist a rule in a database?
Consider this simple scenario
#0 or more facts with "age" predicate
engine << ["mary", "age", 15]
engine << ["paul", "age", 22]
engine << ["fred", "age", 71]
I would like to make gen a new fact that contains the cumulative age of all of the persons (or the average, or any arbitrary reduce block)
My current (presumably naive) approach is to consolidate pairs into incremental "generations"
Let's take the cumulative age example (this is not an implementation, just a series of generations and facts to express how the algorithm works):
# Generation 0
["mary", "age", 15]
["mary", "generation", 0]
["paul", "age", 22]
["paul", "generation", 0]
["fred", "age", 71]
["fred", "generation", 0]
# Sum each tuple of facts (a,b), (b, a), (a,c), (c, a), (b,c), (c,b)
# concatenate the subjects in alphabetical order (to avoid duplicates)
# as the subjects of the new generation
# Generation 1
["mary&paul", "age", 37]
["mary&paul", "generation", 1]
["fred&mary", "age", 86]
["fred&mary", "generation", 1]
["fred&paul", "age", 93]
["fred&paul", "generation", 1]
# Generation 2
["fred&mary&paul", "age", 108]
["fred&mary&paul", "generation", 2]
This approach seems pretty lousy.
Is there a proper way to perform a reduce and make-gen?
The wiki link seems to loop back to the homepage. Bummer.
Hello @ulfurinn,
Is there anyway to build rules based on dynamic dataset.
I have a set of rules in my database. How can I build and add in my engine of dynamic mode.
Thanks!
As mentioned in the readme: "You can only insert new facts into the current state, "retroactive" facts are not allowed."
But I need to add once deleted facts to the engine.
How can I do that?
And how can I reload the engine with facts.
Would you accept a PR that wraps the dsl in a module? Just so the methods aren't defined on Object
.
For example:
module MyModule
extend Wongi::DSL # or include
# ...
rule "foo" do
# ...
end
end
If not willing, what's your motivation for putting them at the top level? I suppose one downside is that it could break other peoples' code who are relying on it being on Object
?
Thanks :)
I'm developing rails application.
I set up wongi-engine for rule-engine in my application.
I try to write my rule, but I can't.
My rule is to find a member who has a value larger than critical value.
Plz tell me how to write.
following, I tried it.
engine << ["Alex", "Value", 100]
engine << ["Caley", "Value", 200]
master = engine.rule "master" do
forall {
greater "Value", 100
}
end
I expect Caley as the result.
say i have:
engine << Wongi:Engine:Ruleset["TestRules"]
then later I want to remove the Ruleset["TestRules"] from the engine, is there a way to do that?
Does anyone have references to larger examples of wongi-engine use?
The wongi-engine is really awesome. Its working great except in this case I get the same action called repeatedly and I'm not sure how to avoid that. Any suggestions would be very appreciated.
I have a relationship, where an Event can have an Actor and a Manager. The action should fire for a fact where the Event is in the same location as the manager and the actor. When there is only one location it seems to work but when there are multiple locations then its called duplicate times. Not sure if this is what I should be doing. I changed the scenario a bit because I don't want to publish production code. I have a database of rules and I'm trying to check each event against the matching rules and execute code for matching events.
Thanks!
-Laura
self.engine.rule do
forall {
has :Event, 'actor_distance', :Actor_distance
has :Event, 'manager_distance', :Manager_distance
has :Event, 'manager', :Manager
has :Event, 'actor', :Actor
has :Event, 'location', :Location
has :Manager, 'location', :Location
has :Manager, 'bill_by_event', 1
has :Manager, 'manager_limit', :Manager_limit
has :Manager, 'manager_lt', :Manager_lt
has :Manager, 'manager_gte', :Manager_gte
}
make {
action { |token|
Rails.logger.info("Rules met #{token[:Event]} for manager bill_by_event.")
}
}
end
end
18EEN9E1 status is scheduled
18EEN9E1 actor_distance is 0.1683
18EEN9E1 location is Downtown Chicago
18EEN9E1 actor is actor-49
18EEN9E1 venue is 267
18EEN9E1 manager manager-37
actor-49 bill_by_event is 1
actor-49 location is Downtown Chicago
actor-49 location is San Francisco
manager-37 location is San Fransisco
Perhaps this is already present and I missed something. But it would be nice if there was a method that would return an array containing all of the rules that have been added to an engine.
You can reproduce by changing maybe_rule_spec.rb like so
it "should pass with missing facts" do
engine << [1, 2, 3]
engine << rule('test') do
forall {
has 1, 2, :X
maybe :X, 4, :Y
}
end
prod = engine.productions['test']
prod.should have(1).tokens
prod.tokens.first[:X].should == 3
prod.tokens.first[:Y].should be_nil
end
Hi,
First of all, let me thank you for your great work. I am developing my master's thesis using wongi-engine and works fine!
I would like to put a better reference of your work on my thesis. Could you tell me some information about you (name, institution, etc)?
Do you have something else written about Wongi-engine beyond of the Readme file?
Best,
Vagner
If I raise in an action class's execute method, it's silently eaten. Any way to change that behaviour?
Thanks!
I have the following situation in a Rails app.
I have Companies
that perform many services (has_and_belongs_to_many :services
).
I have Incidents
that need certain services (again has_and_belongs_to_many :services
).
Now I need to find all Companies that offer the services needed by a certain Incident. Im not able to wrap my head around the DSL and come up with rules. Would love some help with this π
I'm looking at this gem duplicate
Duplicate.duplicate(@engine)
What I want to do is create a template wongi engine and reuse it over and over again. Originally I was loading all the rules in to one engine all at once but then the engine seems to be getting too big. So another approach I tried was to load the common rules into the engine once, then copy the engine and use the copy so that the engine is only looking for the most recent "target" facts for matching with all the common facts. Hopefully this makes it a smaller set as I noticed that the matching starts out very fast and then slows down considerably.
Let me know if that's something that makes sense to do. I'm not sure that the deep copy is working correctly because now I see duplicate matches. Since it seems like the engine is very complicated/recursive, not sure the deep copy is a good idea.
I would love to hear your thoughts on this.
Thanks!
-Laura
I'm not sure if this is a problem yet, or just the JVM complaining about nothing.
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/filter/asserting_test.rb:14 warning: *' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/alpha_memory.rb:48 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/alpha_memory.rb:52 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/beta/beta_node.rb:130 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:6 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:12 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:18 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl.rb:23 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/dsl_extensions.rb:18 warning: *' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/dsl_extensions.rb:26 warning:
' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/dsl_builder.rb:11 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/extension_clause.rb:15 warning:
' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/extension_clause.rb:28 warning: *' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/extension_clause.rb:32 warning:
_' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/generic_production_rule.rb:16 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/ncc_production_rule.rb:7 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/any_rule.rb:9 warning: &' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/any_rule.rb:15 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/query.rb:18 warning: _' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/dsl/actions/simple_action.rb:7 warning:
*' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/ruleset.rb:60 warning:&' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/ruleset.rb:67 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:148 warning:&' interpreted as argument prefix /Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:154 warning:
&' interpreted as argument prefix
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:376 warning: Statement not reached.
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/network.rb:377 warning: shadowing outer local variable - template
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/graph.rb:36 warning: Ambiguous first argument; make sure.
/Users/chase/.rvm/gems/jruby-1.7.13/gems/wongi-engine-0.0.14/lib/wongi-engine/graph.rb:42 warning: Ambiguous first argument; make sure.
There is a section in the readme about trace:
https://github.com/ulfurinn/wongi-engine#trace-options
It sounds great, but I have no idea how/where to put it or what it does. A concrete example would be spiffy!
We have a rule:
has :Event, 'program_name', "Level 1 Coaching Certification v2"
It's matching facts like:
[:Event, 'program_name', "Level 1 Coaching Certification"]
(note missing v2)
We want to load a bunch of past facts into working memory, then snapshot and then handle new facts. (so just two periods). In the example below, I'd expect to see a single output of "Found a 1, 7, 3", but I'm seeing none.
engine = Wongi::Engine.create
engine.debug!
myrule = engine.rule "added 123" do
forall {
neg 1, :Number, 3, -1
has 1, :Number, 3, 0
}
end
# Past Events
engine << [1, 2, 3]
engine.snapshot!
# New event(s) we are processing
engine << [3, 4, 5]
engine << [4, 5, 6]
engine << [1, 7, 3]
myrule.tokens.each do |token|
puts "Found a 1, #{token[:Number]},3"
end
Furthermore, if I introduce an action into the rule to output, then instead I see one output of "Found a 1, 2, 3" (output before the first snapshot).. then nothing.
I snapshot again after all facts are added, it outputs "Found a 1, 2, 3" (again) and then "Found a 1, 7, 3". I can't seem to figure out how to load past facts in or use timeline features at all.
Seems very promising for us other than that! Thanks in advance!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.