Rule engine path


(Hagen Ivar) #1

Hi!

I want to design a rule engine in Neo4j.
One type of rule is a "inclusion 1-way". If a prameter is included in the input it can give you another parameter which in turn can give another parameter etc. Parameters is a global object and the same parameter can be used in many different rules.

In below example both P1 and P2 is needed for rule1 to be valid.

Rule1 gives P3 which in rule 2 gives P5 and P6. But to get P8 we also need P7 to be chosen.

How do I make a good query to traverse the graph.

Script for creating above example

CREATE (p1:Param {id:"P1"})
CREATE (p2:Param {id:"P2"})
CREATE (p3:Param {id:"P3"})
CREATE (p4:Param {id:"P4"})
CREATE (p5:Param {id:"P5"})
CREATE (p6:Param {id:"P6"})
CREATE (p7:Param {id:"P7"})
CREATE (p8:Param {id:"P8"})
CREATE (p9:Param {id:"P9"})
CREATE (p10:Param {id:"P10"})
CREATE (r1:Regel {id:"REGEL1", type:"inclusion 1-way"})
CREATE (r1)-[:SELECT]->(p1)
CREATE (r1)-[:SELECT]->(p2)
CREATE (r1)-[:INCLUDE]->(p3)
CREATE (r1)-[:INCLUDE]->(p4)

CREATE (r2:Regel {id:"REGEL2", type:"inclusion 1-way"})
CREATE (r2)-[:SELECT]->(p3)
CREATE (r2)-[:INCLUDE]->(p5)
CREATE (r2)-[:INCLUDE]->(p6)

CREATE (r3:Regel {id:"REGEL3", type:"inclusion 1-way"})
CREATE (r3)-[:SELECT]->(p6)
CREATE (r3)-[:SELECT]->(p7)
CREATE (r3)-[:INCLUDE]->(p8)

This is what I've come up with so far for getting the first step

MATCH (p0:Param)<-[rel0:INCLUDE]-(r1:Regel)-[rel1:SELECT]->(p1:Param)
WHERE p1.id IN [ "P1","P2", "P7"] AND r1.type = "inclusion 1-way"
WITH (CASE WHEN COUNT(distinct p1)-SIZE((r1)-[:SELECT]-(:Param)) = 0 THEN 'ok' ELSE 'fel' END) AS check, r1.id AS rid, collect (distinct p0.id) AS incs
WHERE check = 'ok'
RETURN rid, incs

I would like it to return (regel1), P3,P4, (regel2), P5, P6, (regel3), P8 (even P8 since I have P7 as an input parameter).


(Hagen Ivar) #2

So I have created this tree out of the above rules.

MATCH (r:Regel)-[rel]-(p:Param)

WHERE r.type = "inclusion 1-way"

WITH r AS rule,

CASE WHEN type(rel) = "SELECT" THEN p.id ELSE null END AS selpars,

CASE WHEN type(rel) = "INCLUDE" THEN p.id ELSE null END AS incpars

ORDER BY selpars, incpars

WITH rule AS rule, COLLECT(incpars) AS incpars, COLLECT(selpars) AS selpars

UNWIND(incpars) as incpar

WITH rule, selpars, nodes(incpar)

MERGE (t1:TreeNode {id:selpars})

MERGE (t2:TreeNode {id:incpar})

MERGE (t1)-[:NEXT_INCLUDE]->(t2)

MERGE (t1)-[:IN_RULE]->(rule)

Will give me this graph

If I have the in parameters P1,P2, P7 I should get P3, P4, P5, P6 and P8 (since P6,P7 implies P8).
How to write such a query?

If a add another node so that P4 implies P7. Then I will find P6 and P7 in the leafs which should imply that P8 should be included. How can I accomplish this?

CREATE (r4:Regel {id:"REGEL4", type:"inclusion 1-way"})
CREATE (r4)-[:SELECT]->(p4)
CREATE (r4)-[:INCLUDE]->(p7)

MATCH p=(t)-[r:NEXT_INCLUDE*]->() WHERE t.id = ["P1","P2"] RETURN p

╒═════════════════════════════════════════════════════════════╕
│"p" │
╞════════════════════════════════════════════════════════════╡
│[{"id":["P1","P2"]},{},{"id":["P3"]}] │
├────────────────────────────────────────────────────────────┤
│[{"id":["P1","P2"]},{},{"id":["P3"]},{"id":["P3"]},{},{"id":["P5"]}]│
├────────────────────────────────────────────────────────────┤
│[{"id":["P1","P2"]},{},{"id":["P3"]},{"id":["P3"]},{},{"id":["P6"]}]│
├────────────────────────────────────────────────────────────┤
│[{"id":["P1","P2"]},{},{"id":["P4"]}] │
├────────────────────────────────────────────────────────────┤
│[{"id":["P1","P2"]},{},{"id":["P4"]},{"id":["P4"]},{},{"id":["P7"]}]│
└────────────────────────────────────────────────────────────┘