hyperjumptech / grule-rule-engine

Rule engine implementation in Golang
Other
2.2k stars 339 forks source link

Support of DMN Notation or/and Decision Tables #167

Open markuspatrick opened 3 years ago

markuspatrick commented 3 years ago

Hi All,

do you plan a kind of an "import/mapping" based on decision tables? Commonly, a decision table provides a compact and "user understandable" view on a set of rules and their actions.

It would be great, to have a kind of converter from a decision table into the GRL representation of it. Additionally, it exists an OMG Standard, called DMN, to represent complex decision tables or rather models. By doing so, GRULE could be used as a headless fast execution engine, while the definition tables or models can be done in user friendly way somewhere else.

best regards, Markus

newm4n commented 3 years ago

@markuspatrick , After reading your idea to extends Grule capabilities to some how can work with DMN about a month ago, I've been thinking about it, about how it will impact Grule original mission, motivation and intention.

While its certainly, greatly, increase Grule's interoperability with enterprise grade product out there (judging by the big names contributed to the DMN drafts) , It will also move/expands much beyond original idea and intention of grule which is simplicity. Obviously there should be more commitment needed to shift Grule to pursue that capability, and a couple of active opensource developer will not make it at this stage. Too much commitment on my end and perhaps, other grule's contributors too.

For me, I will keep this issue here indefinitely. At least I can hear more support and contributors willing to put their head together in this (perhaps as another open-source project that uses Grule as its engine). the more the merrier. But until that happen, lets make Grule a simple rule engine.

massfords commented 3 years ago

It would be helpful to have a format for a decision table that could be converted to GRL. The standard Drools decision table format is one to consider. This is less work than supporting the full DMN specification.

In my case, I converted my decision table format (a simple CSV) into GRL and it works great.

newm4n commented 3 years ago

@massfords

Thanks a lot for chipping in. Could you kindly help us to get the idea/concept on how you've managed to convert a decision table into GRL.

markuspatrick commented 3 years ago

Hi all,

I have already started the implementation of a small library, which allows the definition of a decision table in golang AND converting into grule rules. Within the table I allow so called S-FEEL-Expressions (Simple Friendly Enough Expression Language). These expressions are converted into grule rules. For validation and converting antlr is used. You can find an good overview about such tables here: https://docs.camunda.org/manual/7.4/reference/dmn11/decision-table/

Open Topics:

Example of building a dTable with the builder:

builder

massfords commented 3 years ago

@newm4n

Here's the basic outline of the simple decision table format I'm using. Please note that this is not a general solution since it doesn't include any of the semantics in the format.

condition1 condition2 condition3 condition4 action1 action2 action3
804 001 - - Generic Label for 804's a b
804 001 1 255 More Specific Label c d
804 001 256 1024 Another Label e f
808 001 - - Generic Label for 808's g h

condition1...n are input conditions action1...n are actions to take

Given the above as input, I traverse each row and generate a GRL snippet using Golang's template library. The snippet for the template is below. There is a small amount of go code that reads the CSV and produces the list of conditions for the when part of the GRL.

grl = template.Must(template.New("grl").Parse(`
rule RuleFromRow{{.RowNum}} salience {{.RowNum}} {
when
    {{range $i, $p := .ToConditions}}{{if ne 0 $i}} && {{end}}DataItemFact.{{$p.FieldName}} {{$p.Op}} {{if ne "Value" .FieldName}}"{{end}}{{$p.FieldValue}}{{if ne "Value" .FieldName}}"{{end}}{{end}}
then
    DataItemMetadata.CategoryLabel = "{{.CategoryLabel}}";
    DataItemMetadata.Hierarchy = "{{.Hierarchy}}"; 
    DataItemMetadata.Desc = "{{.Desc}}"; 
    Complete();
}

The workflow is:

I've done this workflow many times with DROOLS and their specification for Decision Table is really helpful since it reduces the amount of work and documentation I need to do for each table. Having something similar for Grule would welcome. I'm not suggesting my format is it since as I've noted this was a really quick solution and doesn't encode the semantics. I'll revisit this if there's a second table I need to create since I won't want to repeat this processing code.

markuspatrick commented 3 years ago

@massfords : I use the same workflow as you do. Instead of a csv file I use an internal data structure (decision table representation). But it would be easy to "read out" your csv into the internal structure. So you can have a validation of the expressions as well. The building of the rule is done with text/template, as you do.

newm4n commented 3 years ago

@massfords explanation give me sound understanding on how it might/should be. To define a simple table and somehow, translatable to GRL. But still trying to figure out how to make it as generic as possible. One user's decision table structure will be different to others. But the table should be able to accommodate any number of inputs and actions, for each inputs and actions could be flexible enough in their semantics. Enabling the table to be created using a simple excel table would be very helpful to the user. But how?

@markuspatrick approach is quite dynamic where user can create any number of input-entry which can contains logical expression, But how a decision table input field can form something like :

when 
     inputA.abc >= inputB.def

Or am I miss understand the decision table limitation and use on which not intended to be as dynamic as a scripting approach like what GRL can achieve?

markuspatrick commented 3 years ago

@newm4n: The use of input fields as a kind of variables (qualified names) will be possible. For your example it would mean

 ...
 AddInputField("abc", "inputA", model.Integer).
 AddInputField("def", "inputB", model.Integer).
 AddOutputField("out", "result", model.Bool).
  AddRule("R1").
   AddInputEntry(`"<= inputB.def"`, model.SFEEL).  // this is inputA.abc
   AddInputEntry("-", model.SFEEL). //this is inputB.def BUT with a EMPTY sign (will not create any expression in grl)
   AddOutputEntry(true, model.SFEEL). 
...

you can see the idea here, as well : Qualified Names

What makes me more headache are interferences (input fields are part of the output fields as well). So far we do not allow this. In detail, we use Complete(); after each then block to avoid cycles (as you can see in @massfords approach, he do the same). In common, there exists situation, where inteferences are helpful. As far as I understood, we could use 'Retract' to exclude the non inteferencing rules from the next cycle. But not sure, if we could avoid all situations with "max cycle exception" with this approach.

massfords commented 3 years ago

@newm4n The Drools documentation for their format is very good. See: https://docs.jboss.org/drools/release/6.5.0.Final/drools-docs/html/ch06.html#d0e5713

I think it addresses each one of your concerns.

One user's decision table structure will be different to others

I suggest starting with rules as rows like Drools does.

But the table should be able to accommodate any number of inputs and actions

The Drools format supports multiple conditions and actions. The table format identifies each column as a condition or action.

for each inputs and actions could be flexible enough in their semantics

The condition and action columns are associated with a named object from the context. There can be multiple facts for input and multiple objects for output. Each condition column includes info about its operator and how it contributes to DRL generation.

Enabling the table to be created using a simple excel table would be very helpful to the user.

Even with the Drools format there's a fair amount of complexity in the table. One strategy for managing this is to hide and lock rows and columns that contain the import statements or other code snippets that contribute to the DRL generation. Once hidden and locked, the sheet looks like a business document and can be managed as such.

Note: I'm not suggesting you recreate the Drools format. I think it's a good one to review to see how it generates DRL.

newm4n commented 3 years ago

@markuspatrick , since you already started a project like this (Decision Table to GRL) could you kindly tell us your open source project URL and How is your vision with the project with regard of Decision Table ? Because I think, @massfords approach/explanation on the "Drools" table structure is a very good starting point, or addition to yours.

I am all excited about these Decision Table things, but I would rather keep Grule to be as it is, a simple "Rule Engine". Keep it small, do one thing, and do it very good. Thus, I really want to collaborate to other project for a different focus (e.g. Decision Table extension).

markuspatrick commented 3 years ago

@newm4n : I will give you message If the repro is online. So far, we are working on a first small release. After that we will publish it on github (end of this week). Would be really great to welcome you guys as contributors.

Our idea behind the decision table is more from the user perspective. Such table are visualized on the frontend to show and allow business people to configure "business decisions". Its clear, that a decision table is just a "subset" of expressiveness compared to scripted-like GRL-rules (in detail it has the same expressiveness, but it force a CNF -conjunctive normal form-).

I am totally agree with your "do one thing right". I don't think, that such decision tables should part of GRULE lib. It's better to have an external libraries which focus on this "friendly rule definition" for non-developer - and contains possibilities to convert such tables in any rule-engine like GRULE, Drolls, etc.

markuspatrick commented 3 years ago

@newm4n @massfords : A first version of our repository is online. You can found it here: https://github.com/global-soft-ba/decisionTable