Building A Hybrid
Reactive Rule Engine
For
Relational And Graph
Reasoning
Mark Proctor, Mario Fusco, István Ráth, Davide Sottara
The Problem
Student Plans
String name
Plan plan
Student
String code
Student owner
List<Exam> exams
Plan
Plan plan
String course
String code
List<Grade> exams
Exam
Exam exam
int attempt
String value
Grade
1
1
1
0..1
1 0..1
Student Plans
public class Student {

private String name;



private Plan plan;
}
public class Plan {

private String code;

private Student owner;


private List<Exam> exams;

}
public class Exam {
private String code;
private String course;


private Plan plan;


private List<Grade> grades;
}
public class Grade {

private String value;


private int attempt;
private Exam exam;
}
Student Plans
public static Student student(String studentName, String planCode, Exam... exams) {

Student student = new Student(studentName);

Plan plan = new Plan(student, planCode);

student.setPlan( plan );

plan.setOwner( student );

for ( Exam exam : exams ) {

exam.setPlan( plan );

plan.getExams().add ( exam );

}

return student;

}



public static Exam exam( String course, String... grades) {

Exam exam = new Exam( course );

int attempt = 1;

for ( String letter : grades) {

exam.getGrades().add(new Grade(exam, letter, attempt));

attempt++;

}

return exam;

}
Courses
•Communication
•Creed -The Jedi Code
•Force
•Jedi Studies
•Meditation
•Personal
•Situational Awareness
•Spirituality - Jedi Mythology
•Warrior
Student Plans
private static final String A = "A";

private static final String B = "B";

private static final String C = "C";

private static final String D = "D";

private static final String E = "E";

private static final String F = "F";
Student Plans
private static final String A = "A";

private static final String B = "B";

private static final String C = "C";

private static final String D = "D";

private static final String E = "E";

private static final String F = "F";
public void create(KieSession ksession) {

Student darth = student( "Darth", "dp2015",

exam( "dpe01", "Jedi Studies", A),

exam( "dpe02", "Force", B ),

exam( "dpe03", "Meditation", D, C) );

Student yoda = student( "Yoda", "yp2015",

exam( "ype01", "Jedi Studies", A),

exam( "ype02", "Force", A ),

exam( "ype03", "Meditation", A) );

Student luke = student( "Luke", "lp2015",

exam( "lpe01", "Jedi Studies", C, B),

exam( "lpe02", "Force", B ),

exam( "lpe03", "Meditation", F, C) );

}
Student Plans
private static final String A = "A";

private static final String B = "B";

private static final String C = "C";

private static final String D = "D";

private static final String E = "E";

private static final String F = "F";
public void create(KieSession ksession) {

Student darth = student( "Darth", "dp2015",

exam( "dpe01", "Jedi Studies", A),

exam( "dpe02", "Force", B ),

exam( "dpe03", "Meditation", D, C) );

Student yoda = student( "Yoda", "yp2015",

exam( "ype01", "Jedi Studies", A),

exam( "ype02", "Force", A ),

exam( "ype03", "Meditation", A) );

Student luke = student( "Luke", "lp2015",

exam( "lpe01", "Jedi Studies", C, B),

exam( "lpe02", "Force", B ),

exam( "lpe03", "Meditation", F, C) );



ksession.insert( darth );

ksession.insert( yoda );

ksession.insert( luke );

}
Student Plans
• Email all the “Big Data” people their grades.
The Problem
• The information provided is Object Oriented which is a form
of graph and uses references.
• Traditional Production Rule Systems are relational, they
cannot see or use references.
• Users must then map their model to a relational one.
Student Plans
public class Student {

private String name;


private String plan;

}
public class Plan {

private String code;
private String owner;
}
Student Plans
public class Student {

private String name;


private String plan;

}
public class Plan {

private String code;
private String owner;
}
public class Student {

private String name;



private Plan plan;
}
public class Plan {

private String code;

private Student owner;


private List<Exam> exams;

}
Student Plans
public class Grade {

private String value;


private int attempt;
private String exam;
}
public class Exam {
private String code;
private String course;

private String plan;
}
Student Plans
public class Grade {

private String value;


private int attempt;
private String exam;
}
public class Exam {
private String code;
private String course;

private String plan;
}
public class Exam {
private String code;
private String course;


private Plan plan;


private List<Grade> grades;
}
public class Grade {

private String value;


private int attempt;
private Exam exam;
}
Student Plans
• Email all the “Big Data” people their grades.
rule R1 when

$student : Student ()

$plan : Plan ( owner == $student.name )

$exam : Exam( plan == $plan.code, course == ”Big Data” ) 

$grade : Grade( exam == $exam.code )
then
// RHS
end
Rete
AND
AND
OTN OTN OTN OTN
Root
GradeExamPlanStudent
AND
RTN
Rete
public abstract class Node {

protected Node childNode;



public abstract void propagateLeft(Tuple tuple);



public abstract void propagateRight(Object object);

}
Rete
public abstract class Node {

protected Node childNode;



public abstract void propagateLeft(Tuple tuple);



public abstract void propagateRight(Object object);

}
public class AndNode extends Node {

private LeftMemory leftMemory;

private RightMemory rightMemory;

private CompiledExpression expr;



public void propagateLeftInsert(Tuple tuple) {

leftMemory.addTuple(tuple);



for ( Object object : rightMemory.getObjects() ) {

if ( expr.eval(tuple, object) ) {

childNode.propagateLeft(new Tuple(tuple, object));

}

}

}



public void propagateRightInsert(Object object) {

rightMemory.addObject(object);



for ( Tuple tuple : leftMemory.getTuples() ) {

if ( expr.eval(tuple, object) ) {

childNode.propagateLeft(new Tuple(tuple, object));

}

}

}

}
Rete
AND
OTN
Root
Student
[“dp2015”,
“yp2015”,
“lp2015”]
[“darth”,
“yoda”,
“luke”]
[“darth”,
“yoda”,
“luke”]
OTN
Plan
[“dp2015”,
“yp2015”,
“lp2015”]
AND
Exam
Rete
AND
OTN
Root
Student
[“dp2015”,
“yp2015”,
“lp2015”]
[“darth”,
“yoda”,
“luke”]
[“darth”,
“yoda”,
“luke”]
OTN
Plan
[“dp2015”,
“yp2015”,
“lp2015”]
ANDPartial Match
[[“darth”, “dp2015”],
[“yoda”, “yp2015”],
[“luke”, “yp2015”] ]
Exam
public class Tuple {

private Tuple parent;

private Object object;
private List<Tuple> children;




public Tuple(Tuple parent, Object object) {

parent = parent;

this.object = object;

}

}
Rete
AND
OTN
Root
Student
[“dp2015”,
“yp2015”,
“lp2015”]
[“darth”,
“yoda”,
“luke”]
[“darth”,
“yoda”,
“luke”]
OTN
Plan
[“dp2015”,
“yp2015”,
“lp2015”]
ANDPartial Match
[[“darth”, “dp2015”],
[“yoda”, “yp2015”],
[“luke”, “yp2015”] ]
OTN
Exam
[“dpe01”, “dpe02”, “dpe03”,
“ype01”, “ype02”, “ype03”,
“lpe01”, “lpe02”, “lpe03” ]
public class Tuple {

private Tuple parent;

private Object object;
private List<Tuple> children;




public Tuple(Tuple parent, Object object) {

parent = parent;

this.object = object;

}

}
Rete
AND
OTN
Root
Student
[“dp2015”,
“yp2015”,
“lp2015”]
[“darth”,
“yoda”,
“luke”]
[“darth”,
“yoda”,
“luke”]
OTN
Plan
[“dp2015”,
“yp2015”,
“lp2015”]
AND
[[“darth”, “dp2015”, “dpe01”], [“darth”, “dp2015”,“dpe02”],[“darth”, “dp2015”,“dpe03”],
[“yoda”, “yp2015”, “ype01”], [“yoda”, “yp2015”, “ype02”], [“yoda”, “yp2015”, “ype03”],
[“luke”, “lp2015”, “ype01”], [“luke”, “lp2015”, “ype02”], [“luke”, “lp2015”, “ype03”]]
Partial Match
[[“darth”, “dp2015”],
[“yoda”, “yp2015”],
[“luke”, “yp2015”] ]
OTN
Exam
[“dpe01”, “dpe02”, “dpe03”,
“ype01”, “ype02”, “ype03”,
“lpe01”, “lpe02”, “lpe03” ]
public class Tuple {

private Tuple parent;

private Object object;
private List<Tuple> children;




public Tuple(Tuple parent, Object object) {

parent = parent;

this.object = object;

}

}
Rete
[[“darth”, “dp2015”, “dpe01”], [“darth”, “dp2015”,“dpe02”],[“darth”, “dp2015”,“dpe03”],
[“yoda”, “yp2015”, “ype01”], [“yoda”, “yp2015”, “ype02”], [“yoda”, “yp2015”, “ype03”],
[“luke”, “lp2015”, “ype01”], [“luke”, “lp2015”, “ype02”], [“luke”, “lp2015”, “ype03”]]
Darth
dp2015
dpe01 dpe02 dpe03
t1 = new Tuple( null, “Darth” )
t2 = new Tuple( t1, “dp205” )
t3 = new Tuple( t2, “dpe01” )
t4 = new Tuple( t2, “dpe02” )
t5 = new Tuple( t2, “dpe03” )
Exam
Plan
Student
[t1, t2, t3],
[t1, t2, t4],
[t1, t2, t5]
Requirements
• Functionality
• Access child objects via references
• React to child objects
• List comprehension
• Iterate one to many relations
• Support reactive and passive operations
• Implementation
• Syntax Extensions
• Rete Extensions
• Object integration
From
• Implementation
• Introduces one new keyword “from”.
• Requires new Rete node.
• Requires expression evaluation sub system.
• Uses dot ‘.’ as reference accessor.
• with type safe javascript like syntax (MVEL).
• Functionality
• Allows access to nested objects.
• Dot ‘.’ accessor is access and return only.
• It does not provide list comprehension.
• List comprehension is performed by the node on the return result.
• Is passive only, no reactivity.
rule R2 when

$student : Student ( $plan : plan )

$exam: Exam( course == ”Big Data” ) from $plan.exams 

$grade: Grade() from $exam.grades
then

/∗ RHS ∗/ 

end
From
rule R2 when

$student : Student ( $plan : plan )

$exam: Exam( course == ”Big Data” ) from $plan.exams 

$grade: Grade() from $exam.grades
then

/∗ RHS ∗/ 

end
From
From
OTN
Root
Student
RTN
$student : Student ( $plan : plan ) // “from” the Working Memory
$exam: Exam( course == ”Big Data” ) from $plan.exams
$grade: Grade() from $exam.grades
From
public void propagateLeft(Tuple tuple) {

leftMemory.addTuple(tuple);

for ( Object object : rightMemory.getObjects() ) {

if ( expr.eval(tuple, object) ) {

childNode.propagateLeft(new Tuple(tuple, object));

}

}

}
From
public void propagateLeftInsert(Tuple tuple) {

leftMemory.addTuple(tuple);



Object result = expr.equals( tuple.get(index));



if ( result instanceof Collection) {

for ( Object o : ((Collection)result)) {

propagateLeftIfAllowed(tuple, o);

}

} else {

propagateLeftIfAllowed(tuple, result);

}

}



private void propagateLeftIfAllowed(Tuple tuple, Object o) {

if ( isAllowed( tuple, o ) ) {

childNode.propagateLeftInsert(new Tuple(tuple, o));

}

}
public void propagateLeftInsert(Tuple tuple) {

leftMemory.addTuple(tuple);

for ( Object object : rightMemory.getObjects() ) {

if ( expr.eval(tuple, object) ) {

childNode.propagateLeft(new Tuple(tuple, object));

}

}

}
From
public class FromNode extends Node {

private LeftMemory leftMemory;

private CompiledExpression expr;

private int index;



public void propagateLeftInsert(Tuple tuple) {

leftMemory.addTuple(tuple);



Object result = expr.equals( tuple.get(index));



if ( result instanceof Collection) {

for ( Object o : ((Collection)result)) {

propagateLeftIfAllowed(tuple, o);

}

} else {

propagateLeftIfAllowed(tuple, result);

}

}



private void propagateLeftIfAllowed(Tuple tuple, Object o) {

if ( isAllowed( tuple, o ) ) {

childNode.propagateLeftInsert(new Tuple(tuple, o));

}

}


public void propagateRightInsert(Object object) {

// From has no right propagation 

}

}
Passive OOPath
• Implementation
• Re-use ‘from’ node
• Introduces no Rete changes.
• Requires expression evaluation sub system.
• Uses forward slash ‘/’ as reference accessor.
• Introduce XPath inspired syntax
• Syntax change must be added to Patterns
• Functionality
• Allows access to nested objects.
• forward slash ‘/’ accessor performs list comprehension

for each visited reference.
• List comprehension is also performed by the node on the return result.
• Is passive only, no reactivity.
rule R3 when

Student( $grade: /plan/exams{course == ”Big Data”}/grades )
then
/∗ RHS ∗/
end
R1, R2, R3
rule R1 when

$student : Student ()

$plan : Plan ( owner == $student.name )

$exam : Exam( plan == $plan.code, course == ”Big Data” ) 

$grade : Grade( exam == $exam.code )
then
// RHS
end
rule R2 when

$student : Student ( $plan : plan )

$exam: Exam( course == ”Big Data” ) from $plan.exams 

$grade: Grade() from $exam.grades
then

/∗ RHS ∗/ 

end
rule R3 when

Student( $grade: /plan/exams{course == ”Big Data”}/grades )
then
/∗ RHS ∗/
end
OOPath Syntax
• Access by index
• Inline cast for type safety
• Indexed back reference
• Variable back reference
• Back tracking
• Out of Pattern use
Student( $grade : /plan/exams[0]{ course == ”Big Data”}/grades )
Student( $grade : /plan/exams{ #PracticalExam, lab == ”hazard safe”, 

course == ”Material Explosions”}/grades )
A( $var: /b/c/d{ f1 == ../../f2}/e ) // the ../../ back references to the ‘b’ field access
A( $var: /$b : b/c/d{ f1 == $b.f2}/e ) // the $b is inline bound for later use
A( $var: /$b : b/c/d{ f1 == $b.f2}/$b/f2 ) // $var is bound to results of the f2 access
$student : Student()

$grade : /$student/plan/exams{course == ”Big Data”}/grades;
Advanced OOPath Usage
• Use existing Drools syntax and functionality
• Colon ‘:’ provides Pattern and field binding
• Colon with equals ‘:=‘ provides unification
• POSL-like support for position and slotted
• Arguments can be named or positional.
• Positional arguments must come first and be delimited
with a semi colon ‘;’ at the end.
• Positional arguments are always unified, compared to
named arguments which can be bound ’:’ or unified ’:=’.
Advanced OOPath Usage
• Transitive closure
query isContainedIn ( Thing $x , Thing $y )

/$y/$x := children ;

or

/$y/$z := children; and isContainedIn($x, $z;) ) 

end
Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
query isContainedIn ( Thing $x , Thing $y )

/$y/$x := children ;

or

/$y/$z := children; and isContainedIn($x, $z;) ) 

end
query isNotContainedIn ( Thing $x , Thing $y ) 

not( isContainedIn( $x, $y; ) ) 

end
Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
• Accumulation
query isContainedIn ( Thing $x , Thing $y )

/$y/$x := children ;

or

/$y/$z := children; and isContainedIn($x, $z;) ) 

end
query isNotContainedIn ( Thing $x , Thing $y ) 

not( isContainedIn( $x, $y; ) ) 

end
query countItems ( Thing $y)

acc( isContainedIn( $x, $y; ); 

count( $x ); ) 

end
Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
• Accumulation
• Structural Control
query isContainedIn ( Thing $x , Thing $y )

/$y/$x := children ;

or

/$y/$z := children; and isContainedIn($x, $z;) ) 

end
query isNotContainedIn ( Thing $x , Thing $y ) 

not( isContainedIn( $x, $y; ) ) 

end
query countItems ( Thing $y)

acc( isContainedIn( $x, $y; ); 

count( $x ); ) 

end
query childrenOrderedByEdgeCount( Parent $x, Child $c0, int index ) 

/$x/$c1 : children[index]{children.size <= $c0.children. size }; 

childrenOrderedByEdgeCount ( $x , $c1 , index + 1; ) 

end
Advanced OOPath Usage
• Transitive closure
• Negation over transitive closure
• Accumulation
• Structural Control
• Combined Graph and Relational
query isContainedIn ( Thing $x , Thing $y )

/$y/$x := children ;

or

/$y/$z := children; and isContainedIn($x, $z;) ) 

end
query isNotContainedIn ( Thing $x , Thing $y ) 

not( isContainedIn( $x, $y; ) ) 

end
query countItems ( Thing $y)

acc( isContainedIn( $x, $y; ); 

count( $x ); ) 

end
query childrenOrderedByEdgeCount( Parent $x, Child $c0, int index ) 

/$x/$c1 : children[index]{children.size <= $c0.children. size }; 

childrenOrderedByEdgeCount ( $x , $c1 , index + 1; ) 

end
query findChildrenWithMatchingEdgeCounts( Parent $x, Child $c0, int index )

/$x/$c := children[index];

// relational search

exists( Thing( children . size == $c. children . size ) ) 

findChildrenWithMatchingEdgeCounts( $x , $c1 , index + 1;) 

end
Reactive OOPath
• Implementation
• New reactive ‘from’ node.
• ReactiveObject Object integration.
• List integration.
• Functionality
• Uses the OOPath syntax, but now all ‘/‘ are reactive.
Reactive OOPathpublic class ReactiveFromNode extends Node {

private LeftMemory leftMemory;

private CompiledExpression expr;

private int index;



public void propagateLeftInsert(Tuple tuple) {

leftMemory.addTuple(tuple);



Object result = expr.equals( tuple.get(index) );



if ( result instanceof ObservableList) {

ObservableList list = (ObservableList) result;

ListObserver observer = new ListObserver(tuple);

tuple.setObserver(observer);

list.addObserver( observer );



for ( Object o : list ) {

propagateLeftIfAllowed(tuple, o);

}

} else {

propagateLeftIfAllowed(tuple, result);

}

}



public void propagateLeftIfAllowed(Tuple tuple, Object o) {

ReactiveObject r = getReactiveObject(o);

r.addTuple(tuple);



if ( isAllowed( tuple, o ) ) {

childNode.propagateLeftInsert(new Tuple(tuple, o));

}

}



public void propagateChildLeftTupleDelete(Tuple tuple) {

tuple.unlink();

childNode.propagateLeftDelete(tuple);

}
ReactiveObject
public class ReactiveObject {

private List<Tuple> tuples = new ArrayList<Tuple>();

private Object object;



public ReactiveObject(Object object) {

this.object = object;

}





public void addTuple(Tuple tuple) {

tuples.add(tuple);

}



public void removeTuple(Tuple tuple) {

tuples.remove(tuple);

}



protected void notifyUpdate() {

for ( Tuple tuple : tuples ) {

ReactiveFromNode node = (ReactiveFromNode) tuple.getNode();

for ( Tuple childTuple : tuple.getChildren() ) {

if ( childTuple.getObject() == object ) {

node.propagateChildLeftTupleDelete(childTuple);

node.propagateLeftIfAllowed(tuple, object);

break;

}

}

}

}

}

ReactiveObject
public class MyClass {

private String name;
private ReactiveObject delegate = new ReactiveObject(this);



protected void setName(String name) {
this.name = name;
delegate.notifyUpdate()

}

}
public class MyClass extends ReactiveObject {

private String name;
public void MyClass() {
super(name);

}


protected void setName(String name) {
this.name = name;
notifyUpdate()

}

}
Benchmark
rule R1 when

$student : Student ()

$plan : Plan ( owner == $student.name )

$exam : Exam( plan == $plan.code, course == ”Big Data” ) 

$grade : Grade( exam == $exam.code )
then
// RHS
end
rule R2 when

$student : Student ( $plan : plan )

$exam: Exam( course == ”Big Data” ) from $plan.exams 

$grade: Grade() from $exam.grades
then

/∗ RHS ∗/ 

end
rule R3 when

Student( $grade: /plan/exams{course == ”Big Data”}/grades )
then
/∗ RHS ∗/
end
Benchmark
Benchmark
• Visiting a tree with a relational strategy
• Visiting a tree with an Object-Oriented strategy
query findNodesWithValue( Node $from, int $value , List list ) 

Edge( $n : to, $v : to.value ) from $from.outEdges

eval( $v != $value || ( $v == $value && list .add( $n ) ) ) 

findNodesWithValue ( $n , $value , list; ) 

end
query findNodesWithValue( int $id , int $value , List list ) $n: Node( id == $id, $v : value ) 

eval( $v != $value || ( $v == $value && list .add( $n ) ) ) 

Edge( fromId == $id , $toId : toId )

findNodesWithValue ( $toId , $value , list; ) 

end
Related Work
• EMF-IncQuery
• XPath
• SPARQL
• Gremlin
• JXPath
Conclusion and Future Work
• Integrated bytecode weavers for ReactiveObject
• Externalise ReactiveObject
• Use PropertyChangeListener
• Make work with PropertyReactive

RuleML2015 : Hybrid Relational and Graph Reasoning

  • 1.
    Building A Hybrid ReactiveRule Engine For Relational And Graph Reasoning Mark Proctor, Mario Fusco, István Ráth, Davide Sottara
  • 3.
  • 4.
    Student Plans String name Planplan Student String code Student owner List<Exam> exams Plan Plan plan String course String code List<Grade> exams Exam Exam exam int attempt String value Grade 1 1 1 0..1 1 0..1
  • 5.
    Student Plans public classStudent {
 private String name;
 
 private Plan plan; } public class Plan {
 private String code;
 private Student owner; 
 private List<Exam> exams;
 } public class Exam { private String code; private String course; 
 private Plan plan; 
 private List<Grade> grades; } public class Grade {
 private String value; 
 private int attempt; private Exam exam; }
  • 6.
    Student Plans public staticStudent student(String studentName, String planCode, Exam... exams) {
 Student student = new Student(studentName);
 Plan plan = new Plan(student, planCode);
 student.setPlan( plan );
 plan.setOwner( student );
 for ( Exam exam : exams ) {
 exam.setPlan( plan );
 plan.getExams().add ( exam );
 }
 return student;
 }
 
 public static Exam exam( String course, String... grades) {
 Exam exam = new Exam( course );
 int attempt = 1;
 for ( String letter : grades) {
 exam.getGrades().add(new Grade(exam, letter, attempt));
 attempt++;
 }
 return exam;
 }
  • 7.
    Courses •Communication •Creed -The JediCode •Force •Jedi Studies •Meditation •Personal •Situational Awareness •Spirituality - Jedi Mythology •Warrior
  • 8.
    Student Plans private staticfinal String A = "A";
 private static final String B = "B";
 private static final String C = "C";
 private static final String D = "D";
 private static final String E = "E";
 private static final String F = "F";
  • 9.
    Student Plans private staticfinal String A = "A";
 private static final String B = "B";
 private static final String C = "C";
 private static final String D = "D";
 private static final String E = "E";
 private static final String F = "F"; public void create(KieSession ksession) {
 Student darth = student( "Darth", "dp2015",
 exam( "dpe01", "Jedi Studies", A),
 exam( "dpe02", "Force", B ),
 exam( "dpe03", "Meditation", D, C) );
 Student yoda = student( "Yoda", "yp2015",
 exam( "ype01", "Jedi Studies", A),
 exam( "ype02", "Force", A ),
 exam( "ype03", "Meditation", A) );
 Student luke = student( "Luke", "lp2015",
 exam( "lpe01", "Jedi Studies", C, B),
 exam( "lpe02", "Force", B ),
 exam( "lpe03", "Meditation", F, C) );
 }
  • 10.
    Student Plans private staticfinal String A = "A";
 private static final String B = "B";
 private static final String C = "C";
 private static final String D = "D";
 private static final String E = "E";
 private static final String F = "F"; public void create(KieSession ksession) {
 Student darth = student( "Darth", "dp2015",
 exam( "dpe01", "Jedi Studies", A),
 exam( "dpe02", "Force", B ),
 exam( "dpe03", "Meditation", D, C) );
 Student yoda = student( "Yoda", "yp2015",
 exam( "ype01", "Jedi Studies", A),
 exam( "ype02", "Force", A ),
 exam( "ype03", "Meditation", A) );
 Student luke = student( "Luke", "lp2015",
 exam( "lpe01", "Jedi Studies", C, B),
 exam( "lpe02", "Force", B ),
 exam( "lpe03", "Meditation", F, C) );
 
 ksession.insert( darth );
 ksession.insert( yoda );
 ksession.insert( luke );
 }
  • 11.
    Student Plans • Emailall the “Big Data” people their grades.
  • 12.
    The Problem • Theinformation provided is Object Oriented which is a form of graph and uses references. • Traditional Production Rule Systems are relational, they cannot see or use references. • Users must then map their model to a relational one.
  • 13.
    Student Plans public classStudent {
 private String name; 
 private String plan;
 } public class Plan {
 private String code; private String owner; }
  • 14.
    Student Plans public classStudent {
 private String name; 
 private String plan;
 } public class Plan {
 private String code; private String owner; } public class Student {
 private String name;
 
 private Plan plan; } public class Plan {
 private String code;
 private Student owner; 
 private List<Exam> exams;
 }
  • 15.
    Student Plans public classGrade {
 private String value; 
 private int attempt; private String exam; } public class Exam { private String code; private String course;
 private String plan; }
  • 16.
    Student Plans public classGrade {
 private String value; 
 private int attempt; private String exam; } public class Exam { private String code; private String course;
 private String plan; } public class Exam { private String code; private String course; 
 private Plan plan; 
 private List<Grade> grades; } public class Grade {
 private String value; 
 private int attempt; private Exam exam; }
  • 17.
    Student Plans • Emailall the “Big Data” people their grades. rule R1 when
 $student : Student ()
 $plan : Plan ( owner == $student.name )
 $exam : Exam( plan == $plan.code, course == ”Big Data” ) 
 $grade : Grade( exam == $exam.code ) then // RHS end
  • 18.
    Rete AND AND OTN OTN OTNOTN Root GradeExamPlanStudent AND RTN
  • 19.
    Rete public abstract classNode {
 protected Node childNode;
 
 public abstract void propagateLeft(Tuple tuple);
 
 public abstract void propagateRight(Object object);
 }
  • 20.
    Rete public abstract classNode {
 protected Node childNode;
 
 public abstract void propagateLeft(Tuple tuple);
 
 public abstract void propagateRight(Object object);
 } public class AndNode extends Node {
 private LeftMemory leftMemory;
 private RightMemory rightMemory;
 private CompiledExpression expr;
 
 public void propagateLeftInsert(Tuple tuple) {
 leftMemory.addTuple(tuple);
 
 for ( Object object : rightMemory.getObjects() ) {
 if ( expr.eval(tuple, object) ) {
 childNode.propagateLeft(new Tuple(tuple, object));
 }
 }
 }
 
 public void propagateRightInsert(Object object) {
 rightMemory.addObject(object);
 
 for ( Tuple tuple : leftMemory.getTuples() ) {
 if ( expr.eval(tuple, object) ) {
 childNode.propagateLeft(new Tuple(tuple, object));
 }
 }
 }
 }
  • 21.
  • 22.
    Rete AND OTN Root Student [“dp2015”, “yp2015”, “lp2015”] [“darth”, “yoda”, “luke”] [“darth”, “yoda”, “luke”] OTN Plan [“dp2015”, “yp2015”, “lp2015”] ANDPartial Match [[“darth”, “dp2015”], [“yoda”,“yp2015”], [“luke”, “yp2015”] ] Exam public class Tuple {
 private Tuple parent;
 private Object object; private List<Tuple> children; 
 
 public Tuple(Tuple parent, Object object) {
 parent = parent;
 this.object = object;
 }
 }
  • 23.
    Rete AND OTN Root Student [“dp2015”, “yp2015”, “lp2015”] [“darth”, “yoda”, “luke”] [“darth”, “yoda”, “luke”] OTN Plan [“dp2015”, “yp2015”, “lp2015”] ANDPartial Match [[“darth”, “dp2015”], [“yoda”,“yp2015”], [“luke”, “yp2015”] ] OTN Exam [“dpe01”, “dpe02”, “dpe03”, “ype01”, “ype02”, “ype03”, “lpe01”, “lpe02”, “lpe03” ] public class Tuple {
 private Tuple parent;
 private Object object; private List<Tuple> children; 
 
 public Tuple(Tuple parent, Object object) {
 parent = parent;
 this.object = object;
 }
 }
  • 24.
    Rete AND OTN Root Student [“dp2015”, “yp2015”, “lp2015”] [“darth”, “yoda”, “luke”] [“darth”, “yoda”, “luke”] OTN Plan [“dp2015”, “yp2015”, “lp2015”] AND [[“darth”, “dp2015”, “dpe01”],[“darth”, “dp2015”,“dpe02”],[“darth”, “dp2015”,“dpe03”], [“yoda”, “yp2015”, “ype01”], [“yoda”, “yp2015”, “ype02”], [“yoda”, “yp2015”, “ype03”], [“luke”, “lp2015”, “ype01”], [“luke”, “lp2015”, “ype02”], [“luke”, “lp2015”, “ype03”]] Partial Match [[“darth”, “dp2015”], [“yoda”, “yp2015”], [“luke”, “yp2015”] ] OTN Exam [“dpe01”, “dpe02”, “dpe03”, “ype01”, “ype02”, “ype03”, “lpe01”, “lpe02”, “lpe03” ] public class Tuple {
 private Tuple parent;
 private Object object; private List<Tuple> children; 
 
 public Tuple(Tuple parent, Object object) {
 parent = parent;
 this.object = object;
 }
 }
  • 25.
    Rete [[“darth”, “dp2015”, “dpe01”],[“darth”, “dp2015”,“dpe02”],[“darth”, “dp2015”,“dpe03”], [“yoda”, “yp2015”, “ype01”], [“yoda”, “yp2015”, “ype02”], [“yoda”, “yp2015”, “ype03”], [“luke”, “lp2015”, “ype01”], [“luke”, “lp2015”, “ype02”], [“luke”, “lp2015”, “ype03”]] Darth dp2015 dpe01 dpe02 dpe03 t1 = new Tuple( null, “Darth” ) t2 = new Tuple( t1, “dp205” ) t3 = new Tuple( t2, “dpe01” ) t4 = new Tuple( t2, “dpe02” ) t5 = new Tuple( t2, “dpe03” ) Exam Plan Student [t1, t2, t3], [t1, t2, t4], [t1, t2, t5]
  • 26.
    Requirements • Functionality • Accesschild objects via references • React to child objects • List comprehension • Iterate one to many relations • Support reactive and passive operations • Implementation • Syntax Extensions • Rete Extensions • Object integration
  • 27.
    From • Implementation • Introducesone new keyword “from”. • Requires new Rete node. • Requires expression evaluation sub system. • Uses dot ‘.’ as reference accessor. • with type safe javascript like syntax (MVEL). • Functionality • Allows access to nested objects. • Dot ‘.’ accessor is access and return only. • It does not provide list comprehension. • List comprehension is performed by the node on the return result. • Is passive only, no reactivity. rule R2 when
 $student : Student ( $plan : plan )
 $exam: Exam( course == ”Big Data” ) from $plan.exams 
 $grade: Grade() from $exam.grades then
 /∗ RHS ∗/ 
 end
  • 28.
    From rule R2 when
 $student: Student ( $plan : plan )
 $exam: Exam( course == ”Big Data” ) from $plan.exams 
 $grade: Grade() from $exam.grades then
 /∗ RHS ∗/ 
 end From From OTN Root Student RTN $student : Student ( $plan : plan ) // “from” the Working Memory $exam: Exam( course == ”Big Data” ) from $plan.exams $grade: Grade() from $exam.grades
  • 29.
    From public void propagateLeft(Tupletuple) {
 leftMemory.addTuple(tuple);
 for ( Object object : rightMemory.getObjects() ) {
 if ( expr.eval(tuple, object) ) {
 childNode.propagateLeft(new Tuple(tuple, object));
 }
 }
 }
  • 30.
    From public void propagateLeftInsert(Tupletuple) {
 leftMemory.addTuple(tuple);
 
 Object result = expr.equals( tuple.get(index));
 
 if ( result instanceof Collection) {
 for ( Object o : ((Collection)result)) {
 propagateLeftIfAllowed(tuple, o);
 }
 } else {
 propagateLeftIfAllowed(tuple, result);
 }
 }
 
 private void propagateLeftIfAllowed(Tuple tuple, Object o) {
 if ( isAllowed( tuple, o ) ) {
 childNode.propagateLeftInsert(new Tuple(tuple, o));
 }
 } public void propagateLeftInsert(Tuple tuple) {
 leftMemory.addTuple(tuple);
 for ( Object object : rightMemory.getObjects() ) {
 if ( expr.eval(tuple, object) ) {
 childNode.propagateLeft(new Tuple(tuple, object));
 }
 }
 }
  • 31.
    From public class FromNodeextends Node {
 private LeftMemory leftMemory;
 private CompiledExpression expr;
 private int index;
 
 public void propagateLeftInsert(Tuple tuple) {
 leftMemory.addTuple(tuple);
 
 Object result = expr.equals( tuple.get(index));
 
 if ( result instanceof Collection) {
 for ( Object o : ((Collection)result)) {
 propagateLeftIfAllowed(tuple, o);
 }
 } else {
 propagateLeftIfAllowed(tuple, result);
 }
 }
 
 private void propagateLeftIfAllowed(Tuple tuple, Object o) {
 if ( isAllowed( tuple, o ) ) {
 childNode.propagateLeftInsert(new Tuple(tuple, o));
 }
 } 
 public void propagateRightInsert(Object object) {
 // From has no right propagation 
 }
 }
  • 32.
    Passive OOPath • Implementation •Re-use ‘from’ node • Introduces no Rete changes. • Requires expression evaluation sub system. • Uses forward slash ‘/’ as reference accessor. • Introduce XPath inspired syntax • Syntax change must be added to Patterns • Functionality • Allows access to nested objects. • forward slash ‘/’ accessor performs list comprehension
 for each visited reference. • List comprehension is also performed by the node on the return result. • Is passive only, no reactivity. rule R3 when
 Student( $grade: /plan/exams{course == ”Big Data”}/grades ) then /∗ RHS ∗/ end
  • 33.
    R1, R2, R3 ruleR1 when
 $student : Student ()
 $plan : Plan ( owner == $student.name )
 $exam : Exam( plan == $plan.code, course == ”Big Data” ) 
 $grade : Grade( exam == $exam.code ) then // RHS end rule R2 when
 $student : Student ( $plan : plan )
 $exam: Exam( course == ”Big Data” ) from $plan.exams 
 $grade: Grade() from $exam.grades then
 /∗ RHS ∗/ 
 end rule R3 when
 Student( $grade: /plan/exams{course == ”Big Data”}/grades ) then /∗ RHS ∗/ end
  • 34.
    OOPath Syntax • Accessby index • Inline cast for type safety • Indexed back reference • Variable back reference • Back tracking • Out of Pattern use Student( $grade : /plan/exams[0]{ course == ”Big Data”}/grades ) Student( $grade : /plan/exams{ #PracticalExam, lab == ”hazard safe”, 
 course == ”Material Explosions”}/grades ) A( $var: /b/c/d{ f1 == ../../f2}/e ) // the ../../ back references to the ‘b’ field access A( $var: /$b : b/c/d{ f1 == $b.f2}/e ) // the $b is inline bound for later use A( $var: /$b : b/c/d{ f1 == $b.f2}/$b/f2 ) // $var is bound to results of the f2 access $student : Student()
 $grade : /$student/plan/exams{course == ”Big Data”}/grades;
  • 35.
    Advanced OOPath Usage •Use existing Drools syntax and functionality • Colon ‘:’ provides Pattern and field binding • Colon with equals ‘:=‘ provides unification • POSL-like support for position and slotted • Arguments can be named or positional. • Positional arguments must come first and be delimited with a semi colon ‘;’ at the end. • Positional arguments are always unified, compared to named arguments which can be bound ’:’ or unified ’:=’.
  • 36.
    Advanced OOPath Usage •Transitive closure query isContainedIn ( Thing $x , Thing $y )
 /$y/$x := children ;
 or
 /$y/$z := children; and isContainedIn($x, $z;) ) 
 end
  • 37.
    Advanced OOPath Usage •Transitive closure • Negation over transitive closure query isContainedIn ( Thing $x , Thing $y )
 /$y/$x := children ;
 or
 /$y/$z := children; and isContainedIn($x, $z;) ) 
 end query isNotContainedIn ( Thing $x , Thing $y ) 
 not( isContainedIn( $x, $y; ) ) 
 end
  • 38.
    Advanced OOPath Usage •Transitive closure • Negation over transitive closure • Accumulation query isContainedIn ( Thing $x , Thing $y )
 /$y/$x := children ;
 or
 /$y/$z := children; and isContainedIn($x, $z;) ) 
 end query isNotContainedIn ( Thing $x , Thing $y ) 
 not( isContainedIn( $x, $y; ) ) 
 end query countItems ( Thing $y)
 acc( isContainedIn( $x, $y; ); 
 count( $x ); ) 
 end
  • 39.
    Advanced OOPath Usage •Transitive closure • Negation over transitive closure • Accumulation • Structural Control query isContainedIn ( Thing $x , Thing $y )
 /$y/$x := children ;
 or
 /$y/$z := children; and isContainedIn($x, $z;) ) 
 end query isNotContainedIn ( Thing $x , Thing $y ) 
 not( isContainedIn( $x, $y; ) ) 
 end query countItems ( Thing $y)
 acc( isContainedIn( $x, $y; ); 
 count( $x ); ) 
 end query childrenOrderedByEdgeCount( Parent $x, Child $c0, int index ) 
 /$x/$c1 : children[index]{children.size <= $c0.children. size }; 
 childrenOrderedByEdgeCount ( $x , $c1 , index + 1; ) 
 end
  • 40.
    Advanced OOPath Usage •Transitive closure • Negation over transitive closure • Accumulation • Structural Control • Combined Graph and Relational query isContainedIn ( Thing $x , Thing $y )
 /$y/$x := children ;
 or
 /$y/$z := children; and isContainedIn($x, $z;) ) 
 end query isNotContainedIn ( Thing $x , Thing $y ) 
 not( isContainedIn( $x, $y; ) ) 
 end query countItems ( Thing $y)
 acc( isContainedIn( $x, $y; ); 
 count( $x ); ) 
 end query childrenOrderedByEdgeCount( Parent $x, Child $c0, int index ) 
 /$x/$c1 : children[index]{children.size <= $c0.children. size }; 
 childrenOrderedByEdgeCount ( $x , $c1 , index + 1; ) 
 end query findChildrenWithMatchingEdgeCounts( Parent $x, Child $c0, int index )
 /$x/$c := children[index];
 // relational search
 exists( Thing( children . size == $c. children . size ) ) 
 findChildrenWithMatchingEdgeCounts( $x , $c1 , index + 1;) 
 end
  • 41.
    Reactive OOPath • Implementation •New reactive ‘from’ node. • ReactiveObject Object integration. • List integration. • Functionality • Uses the OOPath syntax, but now all ‘/‘ are reactive.
  • 42.
    Reactive OOPathpublic classReactiveFromNode extends Node {
 private LeftMemory leftMemory;
 private CompiledExpression expr;
 private int index;
 
 public void propagateLeftInsert(Tuple tuple) {
 leftMemory.addTuple(tuple);
 
 Object result = expr.equals( tuple.get(index) );
 
 if ( result instanceof ObservableList) {
 ObservableList list = (ObservableList) result;
 ListObserver observer = new ListObserver(tuple);
 tuple.setObserver(observer);
 list.addObserver( observer );
 
 for ( Object o : list ) {
 propagateLeftIfAllowed(tuple, o);
 }
 } else {
 propagateLeftIfAllowed(tuple, result);
 }
 }
 
 public void propagateLeftIfAllowed(Tuple tuple, Object o) {
 ReactiveObject r = getReactiveObject(o);
 r.addTuple(tuple);
 
 if ( isAllowed( tuple, o ) ) {
 childNode.propagateLeftInsert(new Tuple(tuple, o));
 }
 }
 
 public void propagateChildLeftTupleDelete(Tuple tuple) {
 tuple.unlink();
 childNode.propagateLeftDelete(tuple);
 }
  • 43.
    ReactiveObject public class ReactiveObject{
 private List<Tuple> tuples = new ArrayList<Tuple>();
 private Object object;
 
 public ReactiveObject(Object object) {
 this.object = object;
 }
 
 
 public void addTuple(Tuple tuple) {
 tuples.add(tuple);
 }
 
 public void removeTuple(Tuple tuple) {
 tuples.remove(tuple);
 }
 
 protected void notifyUpdate() {
 for ( Tuple tuple : tuples ) {
 ReactiveFromNode node = (ReactiveFromNode) tuple.getNode();
 for ( Tuple childTuple : tuple.getChildren() ) {
 if ( childTuple.getObject() == object ) {
 node.propagateChildLeftTupleDelete(childTuple);
 node.propagateLeftIfAllowed(tuple, object);
 break;
 }
 }
 }
 }
 }

  • 44.
    ReactiveObject public class MyClass{
 private String name; private ReactiveObject delegate = new ReactiveObject(this);
 
 protected void setName(String name) { this.name = name; delegate.notifyUpdate()
 }
 } public class MyClass extends ReactiveObject {
 private String name; public void MyClass() { super(name);
 } 
 protected void setName(String name) { this.name = name; notifyUpdate()
 }
 }
  • 45.
    Benchmark rule R1 when
 $student: Student ()
 $plan : Plan ( owner == $student.name )
 $exam : Exam( plan == $plan.code, course == ”Big Data” ) 
 $grade : Grade( exam == $exam.code ) then // RHS end rule R2 when
 $student : Student ( $plan : plan )
 $exam: Exam( course == ”Big Data” ) from $plan.exams 
 $grade: Grade() from $exam.grades then
 /∗ RHS ∗/ 
 end rule R3 when
 Student( $grade: /plan/exams{course == ”Big Data”}/grades ) then /∗ RHS ∗/ end
  • 46.
  • 47.
    Benchmark • Visiting atree with a relational strategy • Visiting a tree with an Object-Oriented strategy query findNodesWithValue( Node $from, int $value , List list ) 
 Edge( $n : to, $v : to.value ) from $from.outEdges
 eval( $v != $value || ( $v == $value && list .add( $n ) ) ) 
 findNodesWithValue ( $n , $value , list; ) 
 end query findNodesWithValue( int $id , int $value , List list ) $n: Node( id == $id, $v : value ) 
 eval( $v != $value || ( $v == $value && list .add( $n ) ) ) 
 Edge( fromId == $id , $toId : toId )
 findNodesWithValue ( $toId , $value , list; ) 
 end
  • 48.
    Related Work • EMF-IncQuery •XPath • SPARQL • Gremlin • JXPath
  • 49.
    Conclusion and FutureWork • Integrated bytecode weavers for ReactiveObject • Externalise ReactiveObject • Use PropertyChangeListener • Make work with PropertyReactive