by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Sergiy Nikolayev
    @snikolayev
    You would need to write separate rules that deal with different conditions.
    RajkumarViven
    @RajkumarViven
    ok thanks for your update
    larryPlayabl
    @larryPlayabl

    @snikolayev I saw that you're doing some work on rete optimization, such as this commit here:

    NRules/NRules@6001f4a

    If it'd be helpful, I'd be happy to try a new version with our project and provide a comparison using the Unity 3D Engine's profiler again, as I did in this issue:

    NRules/NRules#200

    If there are two commits you'd like me to do an A/B comparison with, just let me know.

    Or I can wait a bit if there's more you're planning to do.

    larryPlayabl
    @larryPlayabl
    Do you think that changes made in this commit will help with the performance issues I described in that issue?
    Sergiy Nikolayev
    @snikolayev
    @larryPlayabl the optimizations I'm working on will reduce the amount of expression re-evaluations in the rete graph when propagating updates. This does not reduce allocations in join nodes, but you may be able to observe the improvements just due to the reduction of the number of joins. This is however just the first step in improving the performance of the rete graph, so I'm also planning to address allocations more directly.
    larryPlayabl
    @larryPlayabl
    @snikolayev That makes sense. Glad to hear you're planning on continuing improvements, including focusing on allocations. Let me know if I can help with a round of profiling at some point.
    przemekwojcik
    @przemekwojcik
    @snikolayev is there any easy way to find out because of which PatternElement a rule was fired? Once a rule is fired i have an ActionContext available, it has multiple properties. I see something like ActionContext.Rule.LeftHandSide.ChildElements[0]...Conditions[0] - is there a way to find out has that condition fired during processing of a fact?
    larryPlayabl
    @larryPlayabl

    @przemekwojcik Check out ISession.Events.LhsExpressionEvaluatedEvent. This event fires every time a When (LHS) expression is evaluated, and references all rules that contain this expression. You can monitor these events over time to see what is matching for a given rule.

    In a rete net, you have to do a bit of legwork to figure out exactly which pattern matches cause a rule to fire because expressions can be shared between multiple rules, and their results are cached.

    Therefore you need to build some tooling to do monitor and associate evaluations with a given rule firing.

    The NRules debugger visualizer can help to illustrate this for you.
    Sergiy Nikolayev
    @snikolayev
    One thing I would like to add to what @larryPlayabl said is that a rule fires when ALL the patterns on the left-hand side matched. So, it's a bit incorrect to ask "which of them caused the rule to fire", because the answer is "all of them".
    larryPlayabl
    @larryPlayabl
    Good point! I guess I was thinking about the case of an Or, in which case it's a bit less clear.
    Paweł Adamczuk
    @PawelAdamczuk
    Hello! Could somebody point me to a resource that would explain why a concept of a RuleSet is needed? I am making a proof of concept for a product and I can just use a single Rule Set but I suppose this class exists for a reason. I'm pretty new to Business Rules in general.
    Ivan Li
    @ivanycli
    hello. i'm a new nrule user. i wanted to know if it's possible for a rule to add an object into the ctx which can be used by another rule. i'm defining a series of checks across rules and looking for a way to capture all the results in single entity which i'm inserting into the context when the first rule fires. is it better to insert the various results into the ctx then do a session.query from the main caller? i'm open to better approaches to handling this scenario. thanks!
    Sergiy Nikolayev
    @snikolayev
    @PawelAdamczuk a rule set is just a collection of rules. You can then decide which rules to compile based on which rule set they are in. The notion of the rule set does not exist at the DSL level or at execution time (when compiled to a rete graph). In the future rule sets may start playing a bigger role, but right now it's limited to just organizing and filtering rules at a rule model level.
    @ivanycli have you seen docs on forward chaining? https://github.com/NRules/NRules/wiki/Forward-Chaining
    Paweł Adamczuk
    @PawelAdamczuk
    Thank you!
    Ivan Li
    @ivanycli
    Thanks @snikolayev , I'll review the forward chaining documentation
    lucaszacutti
    @lucaszacutti
    Hi! I'm totally newy with nrules, Can I have nested rules? I would like to test a condition applicable to several nested rules and any nested rule with it own sub-condition and/or other nested rules. Is that possible?
    larryPlayabl
    @larryPlayabl
    @lucaszacutti You can't have a nested rule, but you can have rule logic shared between multiple rules. One way to do this is with a base class to a rule. Another is to call utility methods or extension methods that add clauses to your rule. You'll need to pass any context into such utility methods. Check out this page for an example: https://github.com/NRules/NRules/wiki/DSL-Extensions
    tnghub3
    @tnghub3
    Does it support decision table?
    Similar to decision table with drools and brms
    Sergiy Nikolayev
    @snikolayev
    @tnghub3 no, it doesn’t
    tnghub3
    @tnghub3
    Any recommendations on how to do it with nrules?
    larryPlayabl
    @larryPlayabl

    @snikolayev I'm curious to experiment a bit with some resource pooling to try to reduce allocations in NRules. I'd love to hear your thoughts on it when you have a moment.

    One low-hanging-fruit spot I'd like to try is Tuple reuse. It's very clear where Tuples are constructed, and they could instead come from a pool of Tuples which can be reused. Any ideas to help me track down the point/points in the code where can a Tuple be safely returned to the pool for reuse?

    Sergiy Nikolayev
    @snikolayev
    @tnghub3 I suggest you step back and look at the problem you are trying to solve. Decision table is just a tool; see if you can reframe your problem in a way that can be solved with predicate logic/production rules. If so, you can use NRules to encode that logic. If decision tables is the only way to solve your problem, I would look for an appropriate library/framework outside NRules that would allow you to do that.
    Sergiy Nikolayev
    @snikolayev
    @larryPlayabl I think it's a great idea to explore resource pooling. But I don't think Tuples is a good candidate. Tuples in NRules are stateful and long lived. They are also small and not expensive to create. The candidates I'm thinking about are arrays of facts created during expression evaluation, which are allocated and then collected right away. Another candidate is fact enumerator in a tuple, which is created numerous times during fact propagation through the graph. Also, fact lists and tuple lists created during propagation are good candidates for pooling; though these are harder to tackle due to the recursive nature of propagation. One other idea I have is to convert fact propagation from recursive to iterative, at which point pooling fact/tuple lists should be much easier.
    larryPlayabl
    @larryPlayabl

    @snikolayev Thanks for the pointers. Yes, it makes sense to start with the easiest options that offer the greatest optimization for amount of effort and risk. I'll openly admit that I'm not especially well versed in this kind of optimization, and would definitely want to keep you in the loop as I experiment to make sure I'm going in the right direction. I know there can be subtle details in the implementation that may make all the difference in how much allocation savings we're actually reaping.

    The object arrays created in the LHSExpression Invoke methods look like they'd be pretty straightforward to pool. Do you believe that swapping these arrays out for List<object> that are cleared and repopulated each time would offer an allocation advantage?

    If that won't help significantly, I could also imagine caching a Dictionary<ITuple, object[]> to be used by these LHSExpression methods. I believe this would work because the object[] will always be the same size for the Tuple. Obviously, this cache would need to be updated whenever a given tuple's facts change. That could either be done by iterating through them and updating them on each call to Invoke, or by checking for a "dirty" flag on the tuple which would indicate that the facts have changed since the last invoke, though that'd be more complex.

    For the Tuple.Facts IEnumerable, I could give each Tuple a List<Fact> that's cleared and repopulated by walking the tuples on each call to get the IEnumerable. However, again, maybe there'd be a more efficient way to do that and only update the Facts list as needed. Think that'd be possible?

    larryPlayabl
    @larryPlayabl
    Actually, I assume it's possible that the Facts property for a given Tuple will be called while another caller is already iterating through its facts. So that'd mean that clearing the same reusable list with each call wouldn't be safe.
    Sergiy Nikolayev
    @snikolayev
    @larryPlayabl regarding LhsExpression.Invoke, swapping arrays with Lists will likely not change anything, as that's still an allocation (and same array behind the scenes). How about ArrayPool? The rub here is that this is not compatible with .net framework 4.5, so that would significantly change what frameworks NRules targets. Regarding Dictionary caching - hard to say w/o prototyping. My hunch is that stateful stuff that lives together with the Tuple is likely going to be not suitable for pooling. Regarding Tuple.Facts - materializing lists of facts will likely just make it worse. At least right now enumerator is ephemeral. But it is the enumerator itself that's instantiated over and over again, and so I was thinking about pooling the enumerators. It's a bit hard to have a good back and forth here on gitter. How about discussing it here: NRules/NRules#200 ?
    larryPlayabl
    @larryPlayabl
    Sure - I've moved the conversation over to github.
    Gurdeep Sira
    @gurdeepsira
    Hi all, a question... how hard would it be to provide a custom gui for nrules in a web app/
    ?
    Ramanarayan1986
    @Ramanarayan1986
    Please give me a solution to save rule in xml or database
    Sergiy Nikolayev
    @snikolayev
    @gurdeepsira regarding a custom web gui for NRules. It's such a broad question that it's impossible to answer. I'll just leave it at - I don't have any plans to build such a UI.
    Sergiy Nikolayev
    @snikolayev
    @Ramanarayan1986 you cannot save rules in XML with NRules. There are two DSLs for NRules - C# DSL (https://github.com/NRules/NRules/wiki/Fluent-Rules-DSL) and NRules language (https://github.com/NRules/NRules.Language). I would seriously recommend against storing rules in the database, and suggest you compile the rules and deploy them as separate assemblies. If you firmly decided to do it, mostly your options are 1) store C# in the DB and compile on the fly with Roslyn (again, I would seriously recommend against this). 2) use NRules.Language and store textual rules in the DB or 3) write your own specialized DSL, that you would compile into NRules.RuleModel using the RuleBuilder (https://github.com/NRules/NRules/wiki/Rule-Builder).
    Just remember - by doing any of this, instead of using Visual Studio or VS Code for writing C# you are basically giving up an IDE with intellisense, type safety and compile-time checks, debugger, build infrastructure. Also, storing rules in the DB likely means bypassing any SDLC, source control, CI/CD practices, unless you build some heavy process around this. At which point I'm not really sure what you are gaining. IMO
    Gurdeep Sira
    @gurdeepsira
    @snikolayev I have come back to this. I am doing a booking app for a friend and I can write some rules for him anyway, as long as some parameters are added (e.g. number of bookings). So I take it saving rules in JSON is not an option either? I think the seperate assembly approach is better and then inject that (in my case, a microservice will use it).
    Sergiy Nikolayev
    @snikolayev
    @gurdeepsira correct, JSON is not an option either. You can easily parameterize the rules by modeling those parameters as facts, and just matching both the parameters and the facts from your domain model.
    yashad singh
    @yashad.singh_gitlab
    image.png
    Dependency resolver not provided. To use rule dependencies set a dependency resolver on the rules session.
    I am new to NRules and trying to use services in my rules. But it is throwing error "Dependency resolver not provided. To use rule dependencies set a dependency resolver on the rules session.".
    my service variable always set to "null".
    yashad singh
    @yashad.singh_gitlab
    @snikolayev I am working with an API on dot net core. And dependencies have already been injected in serviceContainer in Startup.cs file. So i have no idea how the dependency injection works separately with NRules...
    Sergiy Nikolayev
    @snikolayev
    @yashad.singh_gitlab if you want to use rule dependencies (which are resolved at rules run time), you need to implement and supply an IDependencyResolver (see https://github.com/NRules/NRules/wiki/Rule-Dependencies). Another approach is to inject dependencies into rules classes at rules instantiation time. In this case you need to implement IRuleActivator (see https://github.com/NRules/NRules/wiki/Fluent-Rules-Loading#Rule-Activation). When you implement one or both of these interfaces, you can simply just forward resolution requests to your existing service container.
    Another NRules user I believe took a stab at implementing an integration project between NRules and .net core container: https://github.com/cloudb0x/NRules.Integration.AspNetCore
    yashad singh
    @yashad.singh_gitlab
    image.png

    @snikolayev Is it possible to consume scoped services in MyRule (: Rule)? Currently it only work with Singleton service ( services.AddSingleton<IServiceTest, ServiceTest>(); ).

    When I tried scoped services ( services.AddScoped<IServiceTest, ServiceTest>(); ) it threw an error as shown in the image above.

    Sergiy Nikolayev
    @snikolayev
    @yashad.singh_gitlab you cannot use scoped services with rule activation, because rules are instantiated once during the application lifetime. But you should be able to use them with the runtime rules dependencies, via IDependencyResolver. When implementing the resolver, forward the resolution requests to the scoped service provider, instead of the root service provider. This also means you would have to create a new session per scope, create a dependency resolver for that scope and set it on that session.
    yashad singh
    @yashad.singh_gitlab
    Thanks @snikolayev ... It worked. Thanks a lot.
    yashad singh
    @yashad.singh_gitlab
    image.png
    @snikolayev How can I make this call awaitable in above code in the image? Is it possible?
    Sergiy Nikolayev
    @snikolayev
    @yashad.singh_gitlab no, async actions are not supported