3.2 Drools约束文件编写

964 阅读3分钟

这是我参与更文挑战的第15天,活动详情查看: 更文挑战

内容概要

上一篇章我们学习了,如何使用ConstraintStream方式进行规则约束编写,今天我们来学习下Drools的方式,Drools的方式是非常适合OptaPlanner的方式,但是OptaPlanner有一定的学习成本,但是好处确实巨大的。

使用Drools规则引擎实现的分数计算。每个分数约束都被写成一个或多个分数规则。

优点

  • 支持增量分数计算
    • 因为大多数DRL语法使用前向链,可以进行增量计算而不需要任何额外的代码。
  • 分数约束规则作为单独的规则与代码隔离开
    • 易于添加或者修改规则
  • 通过以下几种方式可以灵活配置规则
    • 使用决策表
      • Excel (XLS) spreadsheet
      • KIE Workbench WebUI
    • 在KIE Workbench资源库中存储和发布
  • 性能优越
    • 在每个版本中,Drools规则引擎都会变得更快

缺点

  • Drools会带来一定的学习成本
  • 对某些公司的技术团队来书,他们不愿意额外学习一门工具或者语言。

Drools文件配置

有几种方法可以定义的Drools文件的位置:

scoreDrl

简单方法。分数规则存在于一个DRL文件中,该文件作为classpath资源被提供。只需在求解器配置中把评分规则DRL文件作为元素加入。

<scoreDirectorFactory>
    <scoreDrl>org/optaplanner/examples/nqueens/solver/nQueensConstraints.drl</scoreDrl>
  </scoreDirectorFactory>

在一个典型的项目中(遵循Maven目录结构),该DRL文件位于$PROJECT_DIR/src/main/resources/org/optaplanner/examples/nqueens/solver/nQueensConstraints.drl。

如果约束规则被分割成多个DRL文件,则添加多个元素。

scoreDrlFile

要使用本地文件系统中的文件,而不是classpath资源,请在求解器配置中添加约束规则DRL文件作为元素。

  <scoreDirectorFactory>
    <scoreDrlFile>/home/ge0ffrey/tmp/nQueensConstraints.drl</scoreDrlFile>
  </scoreDirectorFactory>

如果约束规则被分割到多个DRL文件中,则添加多个元素。

实现简单规则

下面是一个在DRL文件中以分数规则实现分数约束的例子:

rule "Horizontal conflict"
    when
        Queen($id : id, row != null, $i : rowIndex)
        Queen(id > $id, rowIndex == $i)
    then
        scoreHolder.addConstraintMatch(kcontext, -1);
end

这条评分规则将为每两个具有相同行数的皇后则进行扣分处理。(id>$id)这个条件是必要的,以确保对于两个皇后A和B,它只能对(A, B)匹配,而不是对(B, A)、(A, A)或(B, B)。让我们仔细看看这个由四个皇后组成的解决方案的得分规则:

unsolvedNQueens04.png

在这个解决方案中,水平冲突得分规则将为六对皇后夫妇匹配,(A,B),(A,C),(A,D),(B,C),(B,D)和(C,D)。因为没有一个皇后在同一条垂直线或对角线上,这个解决方案的得分是-6。

一个ScoreHolder实例被放入到KieSession中,作为一个名为scoreHolder的全局变量。分数规则需要(直接或间接)更新这个实例以改变分数。

得分权重规则

如果你已经配置了一个ConstraintConfig,那么每个约束的分数级别和分数权重都与约束的实现解耦了,所以它们可以被业务用户更容易地改变。

在这种情况下,使用 ScoreHolder 的 reward() 和 penalize() 方法。

package org.optaplanner.examples.nqueens.solver;
...
global SimpleScoreHolder scoreHolder;

rule "Horizontal conflict"
    when
        Queen($id : id, row != null, $i : rowIndex)
        Queen(id > $id, rowIndex == $i)
    then
        scoreHolder.penalize(kcontext);
end

// Vertical conflict is impossible due the model

rule "Ascending diagonal conflict"
    when
        Queen($id : id, row != null, $i : ascendingDiagonalIndex)
        Queen(id > $id, ascendingDiagonalIndex == $i)
    then
        scoreHolder.penalize(kcontext);
end

rule "Descending diagonal conflict"
    when
        Queen($id : id, row != null, $i : descendingDiagonalIndex)
        Queen(id > $id, descendingDiagonalIndex == $i)
    then
        scoreHolder.penalize(kcontext);
end

它们会根据约束配置中定义的分数权重自动影响每个约束匹配的分数。

drl文件必须定义一个包(否则Drools默认为defaultpkg),并且必须与约束配置的constraintPackage相匹配。

(具体的方法,参考我们2.10 动态调整约束权重这篇文章。

总结

这一篇章的Drools语法,乍一看大家看不懂,但是我们学习Drools规则语法后就会非常的简单。大家可以看下这个教学视频,只要学会了基本的语法其实很简单。www.bilibili.com/video/BV1Pa…

结束语

下一篇章我们来学习一个特殊的变量,Shadow Variable 影子变量,这在某些场景中是非常管重要的。

创作不易,禁止未授权的转载。如果我的文章对您有帮助,就请点赞/收藏/关注鼓励支持一下吧💕💕💕💕💕💕