我应该在这种情况下使用Drools吗?

时间:2010-02-16 17:44:32

标签: java rules drools

我将使用大学的图书馆系统来解释我的用例。学生在图书馆系统中注册并提供他们的个人资料:性别,年龄,部门,以前完成的课程,当前注册的课程,已经借阅的书籍等。图书馆系统中的每本书都将根据学生的个人资料定义一些借阅规则,例如,计算机算法的教科书只能由目前在该课程注册的学生借用;另一本教科书只能由数学系的学生借用;也可能有规则,学生最多只能借2本电脑网络书。由于借用规则,当学生在图书馆系统中搜索/浏览时,他只会看到可以借用的书籍。因此,该要求实际上归结为有效生成学生有资格借阅的书籍清单。

以下是我使用Drools对设计进行设想的方法 - 每本书都有一个规则,对学生档案有一些字段限制作为LHS,书规则的RHS只是将书籍ID添加到全局结果列表中,然后全部书规则被加载到RuleBase中。当学生搜索/浏览图书馆系统时,会从RuleBase创建无状态会话,并且学生的个人资料被断言为事实,然后学生可以借用的每本书都会触发其图书规则并获得完整的图书清单。学生可以在全球结果列表中借阅。

一些假设:图书馆将处理数百万本书;我不认为图书规则太复杂,平均每条规则最多3个简单的字段限制;系统需要处理的学生数量在100K范围内,因此负载相当重。我的问题是:如果加载了一百万本图书规则,Drools会占用多少内存?所有这些百万条规则的解雇速度有多快?如果Drools是合适的,我想听听一些有经验的用户设计这样一个系统的最佳实践。感谢。

5 个答案:

答案 0 :(得分:11)

首先,不要为每本书制定规则。制定限制规则 - 定义的限制比书籍少得多。这将对运行时间和内存使用量产生巨大影响。

通过规则引擎运行大量书籍将会很昂贵。特别是因为您不会向用户显示所有结果:每页只有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来确保只触发一条规则,以及确保按照我希望的顺序触发它们的显着性。

最后,保持缓存规则。 Drools允许 - 并建议您 - 只将规则加载到知识库中一次,然后从中创建会话。知识库价格昂贵,会议便宜。

答案 1 :(得分:7)

我对Drools(或一般规则引擎)的经验是,如果用户对规则的可见性很重要,或者如果快速更改规则而不将其作为编码项目很重要,或者如果一套规则非常庞大,因此很难在代码中进行管理,思考和分析(所以你会让商界人士要求技术人员去阅读代码并告诉他们在情况X中会发生什么)。

话虽如此,规则引擎可能成为瓶颈。它们不会运行任何接近代码性能的东西,因此您需要在架构上预先管理它。在这个特定的情况下,肯定有一个数据库,你可以添加数据库返回查询的性能问题比你在代码中分析整个集合要快得多。

我绝对不会通过制作一百万个规则对象来实现它,而是我会创建一个可以分配多本书的书籍类型,并针对书籍类型运行规则,然后只显示允许的书籍类型。这样,您可以加载类型,通过规则引擎传递它们,然后将允许的类型推送到数据库端的查询,该查询将提取允许类型的书籍列表。

类型变得有点复杂,因为在实践中,一本书可能有两种类型(如果你正在学习某门课程,或者一般来说,如果你是该部门的一部分,则允许),但这种方法应该仍然坚持。

答案 2 :(得分:1)

  

我的问题是:内存会有多少   Drools如果加载一百万   书规?它的速度有多快   所有这些百万条规则要解雇?

你的电脑有多快,你有多少记忆?从某种意义上说,您只能通过构建概念证明并用适当数量的(随机生成的)测试数据填充它来找到答案。我的经验是,Drools比你想象的要快,并且你必须非常了解底层的东西,以便能够预测什么会让它变慢。

请注意,您正在谈论一百万个规则会话事实(即Book对象),而不是一百万个规则。只有少数规则,不会花很长时间。可能很慢的部分是插入百万个对象,因为Drools需要决定将哪些规则放在议程中以用于每个新事实。

令人遗憾的是,我们没有人能够通过一百万个事实找到答案。

至于实现,我的方法是为学生想要签出的每本书插入一个Book对象,收回不允许的书,以及查询以获取剩余(允许的)Book对象,以及获取原因列表的另一个查询。或者,使用具有可在规则中设置的其他boolean allowedString reasonDisallowed属性的RequestedBook对象。

答案 3 :(得分:1)

任何时候我们正在研究大型数据集(这个问题是关于Drools是否适合大型数据集),请在框外思考(如下)。每当我们谈论“数百万个对象”或类似的log-N类型问题时,我认为他们所讨论的工具不一定是问题所在。所以是的,可以使用Drools(或JBoss Rules),但这只会在某种情况下才有意义......

如果你有任何log-N(交叉引用大数据集与输入),我建议使用更新颖的方法,如数据库支持的Bloom Filters。这些可以实现为Java对象,并由Drools引用以进行事实查找(但是在那里进行自定义编码)。

由于Bloom Filters是微小的内存结构,只有基本的insert()/ contains()函数,它们确实有一个缺点......大约1%的误报率。所以这将作为主缓存。如果构建Drools问题通常是“NO”作为答案,Bloom Filter支持的事实表构造查找将是闪电般快速并且具有微小的内存占用(在我的实现中每条记录大约1.1字节)所以1 MB的RAM用于这个案例。然后在“包含”的情况下(可能是误报),使用数据库支持的事实表来澄清。同样,如果在80%的情况下,查找都是错误的,那么Bloom Filter将大大节省内存和时间。否则,每次(内存和速度)纯粹(任何东西 - Drools事实,数据库等)1M记录查找都会非常昂贵。

答案 4 :(得分:-1)

我担心需要将规则数量作为学生数量的函数 - 这可能会让事情变得棘手(这听起来像是最大的问题)。