2016-07-04 65 views
0

我正试图在Drools中创建一个规则,该规则会基于假设的学生获得直接的As来触发。Drools不匹配从反序列化中获得的嵌套对象

import Student 
import Semester 
import java.util.* 

dialect "mvel" 

rule "straight As1" 
    when 
     $s : Student(
      grades != null, 
      $g : grades 
     ) 
     forall(
      Semester(reading == "A", writing == "A", math == "A") from $g 
     ) 
    then 
     System.out.println($s.getId() + ": s all As1: " + $s); 
     System.out.println($s.getId() + ": g all As1: " + $g); 
end 

rule "straight As2" 
    when 
     $s : Student(
      grades != null, 
      $g : grades 
     ) 
     $a : List(size() == $g.size) from 
      collect (Semester(reading == "A", writing == "A", math == "A") from $g) 
    then 
     System.out.println($s.getId() + ": s all As2: " + $s); 
     System.out.println($s.getId() + ": g all As2: " + $g); 
end 

这样做的输出:

001: s all As1: Student{id='001', grades=[{writing=A, reading=A, math=A}, {writing=A, reading=A, math=A}], name='Albert'} 
001: g all As1: [{writing=A, reading=A, math=A}, {writing=A, reading=A, math=A}] 
---------------- 
002: s all As1: Student{id='002', grades=[{writing=B, reading=B, math=B}], name='Bob'} 
002: g all As1: [{writing=B, reading=B, math=B}] 

这里的问题是,鲍勃没有全部作为。我不知道如何得到straight As规则为阿尔伯特而不是火箭 - As1尝试触发一切,而As2尝试不会触发任何事情。

我已经能够编写规则来根据名称进行过滤。在调试这个时,我在getGrades()触发器上有了断点......但是没有一个在getMath(),getWriting()getReading()上的断点被命中。

Student对象(收紧并除去的toString())是:

public class Student { 
    private String id; 
    private List<Semester> grades; 
    private String name; 

    public Student() { } 
    public String getName() { return name; } 
    public String getId() { return id; } 
    public List<Semester> getGrades() { return grades; } 
    public void setName(String name) { this.name = name; } 
    public void setId(String id) { this.id = id; } 
    public void setGrades(List<Semester> grades) { this.grades = grades; } 
} 

相应学期对象(也收紧和toString()中除去):

public class Semester { 
    private String reading; 
    private String writing; 
    private String math; 

    public Semester() { } 
    public String getReading() { return reading; } 
    public String getWriting() { return writing; } 
    public String getMath() { return math; } 
    public void setReading(String reading) { this.reading = reading; } 
    public void setWriting(String writing) { this.writing = writing; } 
    public void setMath(String math) { this.math = math; } 
} 

这些对象是用代码片段实例化:

YamlReader reader = new YamlReader(new FileReader(file)); 
Student student = reader.read(Student.class); 
System.out.println(student.toString()); 
rv.add(student); 

和yaml对象例如:

id: 
    001 
grades: 
    - 
    reading: A 
    writing: A 
    math: A 
    - 
    reading: A 
    writing: A 
    math: A 
name: 
    Albert 

回答

0

使用最简单可行的方法:

rule "straight As1" 
when 
    $s : Student(grades != null, $g : grades) 
    not Semester(reading != "A" || writing != "A" || math != "A") from $g 
then 
    System.out.println($s.getId() + ": s all As1: " + $s); 
    System.out.println($s.getId() + ": g all As1: " + $g); 
end 

我的主,用你的学生和学期:

public class Main { 
private KieSession kieSession; 
private KieScanner kieScanner; 

public void build() throws Exception { 
    KieServices kieServices = KieServices.Factory.get(); 
    KieFileSystem kfs = kieServices.newKieFileSystem(); 

    FileInputStream fis = new FileInputStream("alla/alla.drl"); 
    kfs.write("src/main/resources/simple.drl", 
       kieServices.getResources().newInputStreamResource(fis)); 

    KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll(); 

    Results results = kieBuilder.getResults(); 
    if(results.hasMessages(Message.Level.ERROR)){ 
     System.out.println(results.getMessages()); 
     throw new IllegalStateException("### errors ###"); 
    } 

    KieContainer kieContainer = 
    kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()); 

    KieBase kieBase = kieContainer.getKieBase(); 

    kieSession = kieBase.newKieSession(); 
} 

public void exec(){ 
    Student albert = new Student(); 
    albert.setName("Albert"); 
    albert.setId("001"); 
    albert.getGrades().add(new Semester("A", "A", "A")); 
    albert.getGrades().add(new Semester("A", "A", "A")); 
    kieSession.insert(albert); 

    Student bob = new Student(); 
    bob.setName("Bob"); 
    bob.setId("002"); 
    bob.getGrades().add(new Semester("B", "B", "B")); 
    kieSession.insert(bob); 

    kieSession.fireAllRules(); 
} 

public static void main(String[] args) throws Exception { 
Main m = new Main(); 
    m.build(); 
    m.exec(); 
} 
} 
+0

虽然我会给予这是一个_much_更好的方法,我仍然存在As1(和As3一样)为Albert和Bob开火的问题,而As2也没有为他们中的任何一个开火...并且在学期课程中没有一个断点被击中。我不确定这是规则逻辑的问题,而是“如何将这些数据传送到那里”。 FIWI,我已经把项目的完整代码放在https://github.com/shagie/StudentNotify – user6548046

+0

帮不了你。我的规则适用于我,使用我添加的设置。 (我不打算讨论那个“深奥”的东西)。 – laune

+0

你的演示实际上确定了问题出在哪里。谢谢。由于类型的删除和/或反射,yaml-beans在填写对象列表 - 而不是学期列表。因此,Drools没有确定其下的物体能够匹配。为yaml beans添加提示([diff](https://github.com/shagie/StudentNotify/commit/059ed8e3afb711f102e7f45ac31730275a2f1541#diff-22345e6eb216a125a21d839232446a20))创建了正确的底层对象,drools很高兴。 – user6548046