首先,不要为每一本书制定规则。制定限制规则——定义的限制比书籍少得多。这将对运行时间和内存使用产生巨大影响。
通过规则引擎运行大量书籍将会很昂贵。特别是因为您不会向用户显示所有结果:每页只有 10-50 个。想到的一个想法是使用规则引擎来构建一组查询条件。(我实际上不会这样做——见下文。)
这是我的想法:
rule "Only two books for networking"
when
Student($checkedOutBooks : checkedOutBooks),
Book(subjects contains "networking", $book1 : id) from $checkedOutBooks,
Book(subjects contains "networking", id != $book1) from $checkedOutBooks
then
criteria.add("subject is not 'networking'", PRIORITY.LOW);
end
rule "Books allowed for course"
when
$course : Course($textbooks : textbooks),
Student(enrolledCourses contains $course)
Book($book : id) from $textbooks,
then
criteria.add("book_id = " + $book, PRIORITY.HIGH);
end
但我实际上不会那样做!
这就是我改变问题的方式:不向用户展示书籍是一种糟糕的体验。用户可能想要细读这些书籍以查看下次要获得哪些书籍。显示书籍,但不允许结帐受限制的书籍。这样,每个用户一次只能浏览 1-50 本书。这将是非常活泼的。上述规则将变为:
rule "Allowed for course"
activation-group "Only one rule is fired"
salience 10000
when
// This book is about to be displayed on the page, hence inserted into working memory
$book : Book(),
$course : Course(textbooks contains $book),
Student(enrolledCourses contains $course),
then
//Do nothing, allow the book
end
rule "Only two books for networking"
activation-group "Only one rule is fired"
salience 100
when
Student($checkedOutBooks : checkedOutBooks),
Book(subjects contains "networking", $book1 : id) from $checkedOutBooks,
Book(subjects contains "networking", id != $book1) from $checkedOutBooks,
// This book is about to be displayed on the page, hence inserted into working memory.
$book : Book(subjects contains "networking")
then
disallowedForCheckout.put($book, "Cannot have more than two networking books");
end
我使用activation-group 来确保只触发一条规则,并使用salience 来确保它们按照我希望它们的顺序被触发。
最后,保持规则缓存。Drools 允许并建议您仅将规则加载到知识库中一次,然后从中创建会话。知识库很贵,会话很便宜。